[Codeforces 176B]Word Cut

Description

题库链接

给你两个字符串 \(S\)\(T\) ,准许你 \(k\) 次操作,每次将字符串左右分成两个非空的部分,再交换位置,问你有多少种不同的操作方法将 \(S\) 串变为 \(T\) 串。

\(1\leq k\leq 100000, 1\leq |S|=|T|\leq 1000\)

Solution

容易发现不论经过多少次操作,其操作后的字符串一定是在原字符串上截开两段再拼接而成。

所以不妨记 \(f_{i,j}\) 为操作 \(i\) 次后在 \(j\) 处截开的方案数为 \(f_{i,j}\)

转移就是由 \(i-1\) 中所有 \(\neq j\) 的位置转移过来的。

但复杂度是 \(O(|S|k)\) 的,不太优雅。但其实考虑到所有字符串本质只有与 \(T\) 串相不相同的两种情况,我们不妨记 \(f_{i,0/1}\) 表示操作 \(i\) 次后与 \(T\) 串是否相同的方案数为 \(f_{i,j}\)

这样就可以线性转移了。但是要先 \(O(|S|^2)\) 预处理出 \(same\) ,表示多少个位置断开与 \(T\) 串本质相同。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1000, yzh = 1e9+7;

char s[N+5], t[N+5];
int same, len, f[N*100+5][2], k;

bool check(int x) {
    for (int i = 1; i <= len; i++) {
    if (s[x] != t[i]) return false;
    ++x; if (x > len) x = 1;
    }
    return true;
}
void work() {
    scanf("%s%s", s+1, t+1); len = strlen(s+1); scanf("%d", &k);
    for (int i = 1; i <= len; i++)
    if (check(i)) ++same;
    if (check(1)) f[0][0] = 1; else f[0][1] = 1;
    for (int i = 1; i <= k; i++) {
    f[i][0] = (1ll*f[i-1][0]*(same-1)%yzh+1ll*f[i-1][1]*same%yzh)%yzh;
    f[i][1] = (1ll*f[i-1][0]*(len-same)%yzh+1ll*f[i-1][1]*(len-same-1)%yzh)%yzh;
    }
    printf("%d\n", f[k][0]);
}
int main() {
    work(); return 0;
}

转载于:https://www.cnblogs.com/NaVi-Awson/p/8667818.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值