【字符迁移】

首先分析题意,即给定一个长度为N的字符串S,对其进行Q次操作,每次操作都是对字符串第 l 到 r  位置的字符的同时加 k。需要注意这里的移动是字符表的循环右移,即z+1=a。

 关键问题:给定的Q 和 k 都很大,如果对每次的右移操作单独处理则需要最多2e5次对字符串的右移,很耗费时间,只能通过一部分测试用例。

关键解法:采用差分以及前缀和的方式,可以将右移次数降到O(1)。原因如下:可以利用Q次循环读取操作的时间,设置一个N + 1长度的数组prefix(记录字符串对应位置上字符应该移动的次数)在读取单次操作后,将移动区间的左端点累加 k ,移动区间的右端点的下一位累减 k,最后计算每一位的前缀和,其中如果有超过某一个移动区间的字符,将会减去累减的大小。

#include<cstdio>
#include<vector>     // 引用容器 

//可用typedef long long LL;来简写 
using namespace std;   
int main()
{
    long long N, Q;    
    scanf("%lld %lld", &N, &Q);// 读取字符串长度 N 和操作次数 Q
    //printf("%d %d", N, Q);
    getchar(); // 抵消回车 
    vector<char> S(N);    // 定义一个字符类型容器来存储字符串,大小初始化为 字符串的长度 
    vector<long long> prefix(N + 1);  // 定义一个长整型的容器来存储前缀和,也是每一个字符应该右移的距离,大小为字符串的大小 + 1,方便记录超过移动区间的右端点的抵消值记录 
    for(long long i = 0; i < N; i++)
    {
        scanf("%c", &S[i]); // 读取字符串 
        
    }
    getchar(); // 抵消回车 
    for(long long i = 0; i < Q; i++)
    {

        long long l, r, k;
        scanf("%lld %lld %lld",&l, &r, &k); // 读取每次的操作区间[ l-1, r-1] 
        getchar(); // 抵消回车 
        prefix[l-1] += k; // 同时进行前缀和数组的初始化,将移动区间的左端点 累加 k 
        prefix[r] -= k;  // 将移动区间的右端点的下一位累减 k,目的是将超过 右端点位置的字符右移的距离与之前累加的相抵消 
    }
    
    for(long long i = 1;i <= N; i++)
    {
      prefix[i] += prefix[i-1];  // 将每一位的前缀和计算出来,能够实现将移动区间重叠部分累加,将超过部分累减 
    }
    for(int i = 0; i < N; i++)
    {
      int a = S[i];
      S[i] = (a - 'a' + prefix[i]) % 26 + 'a';  // 每一位字符S[i]与对应位置的移动距离 prefix[i]
    }


    for(long long i = 0; i < S.size(); i++)
    {
      printf("%c", S[i]);
    }
    return 0;
    
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值