【Codeforces 1281C】Cut and Paste | 思维

本文探讨了一种解决字符串问题的高效算法,通过维护前部分串长度,利用last[]数组和vis[]数组计算每次操作对最终串长度的影响,以求解对10^9+7取模的问题。作者分享了从傻瓜式方法到正确思路的转变过程,并提供了C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

给一个串sss(下标从111nnn),和一个变量ititit,初始为000.要你执行xxx次操作,求最后的串长度对109+710^9+7109+7取模的结果.
操作如下:

  1. it+1it+1it+1
  2. 将剪贴板的内容替换为[it,n][it,n][it,n](nnn是当前的串的长度),并在原串中删除[it,n][it,n][it,n]
  3. 在串的末尾把剪贴板内容粘贴sits_{it}sit

题目思路:

靠。。。写的不能再傻逼了。

靠。。。我做法也太傻逼了。

看下正解:

考虑只会执行xxx次,所以先把前x长度的串维护起来就好了。

每次操作都会增加一部分长度,因为前xxx串长度都知道了,第iii个位置也就知道了,增加的长度就是:

(nn−i)∗(s[i])(nn-i)*(s[i])(nni)(s[i])

操…

我的思路:

首先找下规律:

在这里插入图片描述

last[k]last[k]last[k]代表第当前kkk个数字的对长度贡献,c[k]c[k]c[k]代表kkk已经出现了多少次,这样能推出上述公式的规律。

然后n×3n \times 3n×3模拟就好了…

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const int maxn = 1e6+700;
const int M = 1e6+8;
const int mod= 1e9+7;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll last[15],vis[15];
char s[maxn];
int main(){
  int T;scanf("%d",&T);
  while(T--){
    read(n);
    memset(vis,0,sizeof(vis));
    memset(last,0,sizeof(last));
    scanf("%s",s+1);
    int cnt = strlen(s+1);
    for(int i=1;i<=cnt;i++) last[s[i]-'0']++;
    for(int i=1;i;i++){
      if(cnt>=n) break;
      int len = cnt-i;
      for(int j=2;j<=(s[i]-'0');j++){
        for(int x=1;x<=len;x++){
          s[cnt+1] = s[cnt+1-len];
          ++cnt;
          if(cnt>=n) break;
        }
        if(cnt>=n) break;
      }
    }
    s[cnt+1] = '\0';
    //printf("%s\n",s+1);
    int len = strlen(s+1);
    for(int i=1;i<=min(n,len*1ll);i++){
      vis[s[i]-'0']++;
      ll tmp = s[i]-'0';
      for(int k=1;k<=3;k++){
        last[k] = ((vis[k]*(1ll-tmp)%mod+mod)%mod + tmp*last[k])%mod;
      }
    }
    ll ans = 0;
    for(int k=1;k<=3;k++) ans = (ans + last[k])%mod;
    dl(ans);
  }
  return 0;
}
/***
1
24
133321333
***/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只酷酷光儿( CoolGuang)

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值