AtCoder Beginner Contest 249题解(E,F)

E - RLE

题目大意:有一个长度为 N 的只含有小写字母字符串 S ,将S中连续相同的字母用计数法表示,如 aaa -> a3,

aaabbbcc -> a3b3c2。现在要求用计数法表示后长度严格小于原来长度的 S 数量,要求对P取模。

分析:考虑动态规划

​ 设 f[ i ] [ j ]为 长度为 i 的字符串 用计数法表示后长度为 j 的数量 。

​ sum[ i ] [ j ] 为法 f[ i ] [ j ] 前缀和。

当从最开始放字母时 可以放26种,若不是开始,要与前面的不同,只能放25种。

因为 n最多为2000 ,所以最多只有以下四种情况:

​ (1)放入长度为 1~9 的连续字符串 ,用计数法表示后长度为 2。

​ (2)放入长度为 10~99 的连续字符串 ,用计数法表示后长度为 3。

​ (3)放入长度为 100~999 的连续字符串 ,用计数法表示后长度为 4。

​ (4)放入长度为 1000~9999 的连续字符串 ,用计数法表示后长度为 5。

然后注意一下边界即可,具体转移见代码:

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cout << fixed << setprecision(7);
 
    int n;
    cin >> n >> mod;
 
    vector<vector<modint>> f(n+1,vector<modint>(n+1,0));
    vector<vector<modint>> sum(n+1,vector<modint>(n+1,0));
 
    for(int i=1;i<=n;i++){
        int k=1+to_string(i).size();
        if(k<n){
            f[i][k]+=26;//从头开始放
        }
        for(int j=2;j<n;j++){
            f[i][j] += 25*(sum[max(0,i-1)][max(0,j-2)] - sum[max(0,i-10)][max(0,j-2)]);//第一种情况
            f[i][j] += 25*(sum[max(0,i-10)][max(0,j-3)] - sum[max(0,i-100)][max(0,j-3)]);//第二种情况
            f[i][j] += 25*(sum[max(0,i-100)][max(0,j-4)] - sum[max(0,i-1000)][max(0,j-4)]);//第三种情况
            f[i][j] += 25*(sum[max(0,i-1000)][max(0,j-5)] - sum[max(0,i-10000)][max(0,j-5)]);//第四种情况
            sum[i][j] = sum[i-1][j] + f[i][j];
        }
    }
 
    modint ans;
    for(int i=1;i<n;i++){
        ans+=f[n][i];
    }
 
    cout << ans.val();
 
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

F - Ignore Operations

题目大意:最初 x 为 0 ,有 N 个操作 ,操作有2种类型:

​ (1) y 替换 x

​ (2) x 加上y

​ 你可以跳过最多k次操作,求操作完后最大的 x。

分析:考虑贪心。

假如后面有操作1不跳过,前面的操作不用跳了(没必要),所以当考虑某个操作1不跳时,后面的操作1必须全跳。

我们从后往前枚举第i的操作1不跳,把后面操作2为负数的用一个大根堆维护(正数直接加就好了),大小为 k - (已经跳过的操作1个数),然后更新最大值就可以了,具体见代码。

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cout << fixed << setprecision(7);
 
 
    int n,k;
 
    cin >> n >> k;
    vector<pii> a(n+1);
 
    for(int i=1;i<=n;i++) cin >> a[i].fi >> a[i].se;
 
    a[0] = {1,0};
 
    priority_queue<int> pq;
 
    LL sum=0,psum=0,ans=-1e18;
 
    for(int i=n;i>=0;i--){
        int op=a[i].fi,x=a[i].se;
        if(op==1){
            ans = max(ans,x+sum-psum);
            if(k==0) break;
            k--;
            if(pq.size()>k){
                psum-=pq.top();
                pq.pop();
            }
        }else{
            if(x<0){
                if(pq.size()<k){
                    psum+=x;
                    pq.push(x);
                }else if(pq.size()&&pq.top()>x){
                    psum-=pq.top();
                    pq.pop();
                    pq.push(x);
                    psum+=x;
                }
            }
            sum+=x;
        }
    }
 
    cout << ans << '\n';
 
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览31204 人正在系统学习中
  • 5
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

李公全

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他
新手
引导
客服 举报 返回
顶部