Codeforces #349 div1 C. Codeword 组合数学 递推

题目

题目链接:http://codeforces.com/problemset/problem/666/C

题目来源:Codeforces #349 div1

题解

首先需要看出方案数只和模式串的长度有关,和具体的字符无关。

由于模式串的长度和规模为 105 ,则不同长度模式串最多有 105 种,因而如果如果我们若能在线性时间内推出某长度下的结果,复杂就会变成 Θ(nn)

具体记数的过程比较复杂,需要考虑枚举模式串为第一次匹配的情况。

S 为主串,模式串为P ai |S|=i 时的方案数。

ai=026ai1+(n1i1)25i|P| if i<|P| if i|P|

26ai1 包含了第一次匹配在 S1Si1 出现的情况,最后一个位置放啥都行。

(n1i1)25i|P| 是在 Si 才出现第一次匹配的情况。 S1Si1 能匹配 PiP|P|1 Si=P|P| 。最后一位确定,然后在 S1Si1 选择 PiP|P|1 的匹配,即 (n1i1) ,剩余的位置每个位置都含有 25 种可能,因为不能是它之后第一个确定的位置的字符。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
const int N = 1e5+5;
const int MOD = 1e9+7;

LL powmod(LL a, LL b) {
    LL ans = 1;
    for (; b; b >>= 1) {
        if (b & 1) ans = (a * ans) % MOD;
        a = a * a % MOD;
    }
    return ans;
}

int fac[N], inv[N], p25[N];

void init() {
    inv[0] = fac[0] = p25[0] = 1;
    for (int i = 1; i < N; i++) {
        fac[i] = (LL)fac[i-1] * i % MOD;
        inv[i] = powmod(fac[i], MOD-2);
        p25[i] = (LL)p25[i-1] * 25 % MOD;
    }
}

LL C(int n, int m) {
    return (LL)fac[n] * inv[m] % MOD * inv[n-m] % MOD;
}

int a[N], ans[N];
vector<PII> query[N];

void solve(int n) {
    a[n] = 1;
    for (int i = 0; i < n; i++) {
        a[i] = 0;
    }
    for (int i = n+1; i < N; i++) {
        a[i] = (LL)a[i-1] * 26 % MOD;
        a[i] = (a[i] + C(i-1, n-1) * p25[i-n]) % MOD;
    }
    for (auto q : query[n]) {
        ans[q.fi] = a[q.se];
    }
}

char s[N];

int main() {
    init();
    int n, cur, q, x, cnt = 0;
    scanf("%d", &n);
    scanf("%s", s);
    cur = strlen(s);
    for (int i = 0; i < n; i++) {
        scanf("%d", &q);
        if (q == 1) {
            scanf("%s", s);
            cur = strlen(s);
        } else {
            scanf("%d", &x);
            query[cur].push_back(make_pair(cnt++, x));
        }
    }
    for (int i = 0; i < N; i++) {
        if (query[i].size() == 0) continue;
        solve(i);
    }
    for (int i = 0; i < cnt; i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值