C.Cut and Paste

题意:我们由一个以1, 2, 3组成的字符串s开始,s的长度记为|s|,第i个字符记为si
这里有一个光标,光标的位置l在{0, ..., |s|}范围中
如果l = 0,光标的位置在第一个字符前面
如果l = |s|,光标的位置在最后一个字符的后面
如果0 < l < |s|,那么光标的位置在字符sl和sl+1之间

我们有一个字符串c,叫做裁剪板,一开始是空的

这里有3种操作:
1.移动操作:移动光标一步到右边,l增加一次
2.裁剪操作:让Sright右边的字符到c中,让Sleft左边的字符到s中
3.粘贴操作:追加字符串c到字符串s的后面

一开始l的位置为0,我们进行如下的操作:
1.执行移动操作一次
2.执行裁剪操作一次
3.执行粘贴操作Sl次(Sl表示光标位置坐标的数字)
4.如果l == x,停止,否则回到步骤一

输入:
给出t组测试数据,每组测试数据为x(1 <= x <= 10^6),第二行是字符串s

输出:
对于每一组测试,当这些步骤执行完毕后,对s的长度模 10 ^ 9 + 7,输出答案

分析:让我们称\(s^t\)为字符串s经过t轮后的字符串,称\(s^0\)为初始的字符串s,称\(s_i\dots\)为字符串s的后面i个字符,
那么,我们可以得到\(s^t\)\(s^{t-1}\)得到的公式:
\[s^t = s^{t-1} + s^{t-1}_{t+1}\dots\times(s^{t-1}_{t} - 1)\]
其中,+表示连接字符串的意思,这个公式表示原先的字符串再追加上当前光标右边的所有字符乘以光标所在位置的数字-1的次数
那么可以得到如下公式
\[|s^t| = |s^{t-1}| + |s^{t-1}_{t+1}\dots|\times(s^{t-1}_t - 1)\]
因为\(|s_{i+1}\dots| = |s| - i\)
因此如上的公式可以替换成如下的公式:
\[|s^t| = |s^{t-1}| + (|s^{t-1} - t)\times(s^{t-1}_t - 1)\]
增长停止在第x个字符

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

using LL = long long;
const LL mod = 1e9 + 7;

const int N = 1111;

char _s[N];
LL solve() {
    int x;
    scanf("%d%s", &x, _s);
    LL ls = strlen(_s);
    vector<char> s(_s, _s + ls);
    for (int i = 1; i <= x; i++) {
        int v = s[i - 1] - '1';
        if (s.size() < x) {
            vector<char> sub(s.begin() + i, s.end());
            for (int it = 0; it < v; it++) s.insert(s.end(), sub.begin(), sub.end());
        }
        ls = (ls + (ls - i) * v) % mod;
    }
    return ls;
}

int main()
{
    int t;
    scanf("%d", &t);

    while (t--)
    {
        printf("%lld\n", (solve() % mod + mod) % mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pixel-Teee/p/12109799.html
今日推荐