Codeforces 666C C. Codeword 组合数学+DP

C. Codeword
time limit per test
6 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

The famous sculptor Cicasso is a Reberlandian spy!

These is breaking news in Berlandian papers today. And now the sculptor is hiding. This time you give the shelter to the maestro. You have a protected bunker and you provide it to your friend. You set the security system in such way that only you can open the bunker. To open it one should solve the problem which is hard for others but is simple for you.

Every day the bunker generates a codeword s. Every time someone wants to enter the bunker, integer nappears on the screen. As the answer one should enter another integer — the residue modulo 109 + 7 of the number of strings of length n that consist only of lowercase English letters and contain the string s as the subsequence.

The subsequence of string a is a string b that can be derived from the string a by removing some symbols from it (maybe none or all of them). In particular any string is the subsequence of itself. For example, the string "cfo" is the subsequence of the string "codeforces".

You haven't implemented the algorithm that calculates the correct answers yet and you should do that ASAP.

Input

The first line contains integer m (1 ≤ m ≤ 105) — the number of the events in the test case.

The second line contains nonempty string s — the string generated by the bunker for the current day.

The next m lines contain the description of the events. The description starts from integer t — the type of the event.

If t = 1 consider a new day has come and now a new string s is used. In that case the same line contains a new value of the string s.

If t = 2 integer n is given (1 ≤ n ≤ 105). This event means that it's needed to find the answer for the current string s and the value n.

The sum of lengths of all generated strings doesn't exceed 105. All of the given strings consist only of lowercase English letters.

Output

For each query of the type 2 print the answer modulo 109 + 7 on the separate line.

Example
input
3
a
2 2
1 bc
2 5
output
51
162626
Note

In the first event words of the form "a?" and "?a" are counted, where ? is an arbitrary symbol. There are 26 words of each of these types, but the word "aa" satisfies both patterns, so the answer is 51.




给出一个字符串,求包含这个字符串作为子序列的,长度为n的字符串有多少个。


首先,答案和给出的字符串无关,而只与给定串的长度有关。

设p1,p2...pn是这个串第i个字符在构造的串中第一次出现的位置,n为给出的串的长度,则pn之前的、位置不包含在pi当中的字符可以有25种取法,而pl之后的字符有26种取法。

则有这么多种方法。


观察发现给出的字符最多1e5个,说明给出的串的不同长度最多为个(1,2,....),而n最大为1e5.如果可以线性时间内对长度确定的串求出所有询问,问题就能解决。由此将上面的式子改为DP形式:

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

P为串的长度。


由此利用DP,加上阶乘逆元求出组合数即可。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=100005,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f,mod=1e9+7;   
const ld pi=acos(-1.0L);
ll dp[maxn],a[maxn],p[maxn],ans[maxn],inv[maxn],fac[maxn];
char s[maxn];
vector<ll> v[maxn],d[maxn];

ll fastpow(ll base,ll index) {  
    ll sum=base,ans=1;  
    ll i=index;  
    while (i) {  
        if (i%2) ans=(ans*sum)%mod;  
        sum*=sum;  
        sum=sum%mod;  
        i/=2;  
    }  
    return ans;  
}  
  
ll lucas(ll n,ll m){  
    if (n<m) {  
        return 0;  
    } else return p[n]*((inv[m]%mod)*inv[n-m]%mod)%mod;  
}  

int main() {
	int m,len,i,c=0,t,j;
	ll n;
	scanf("%d",&m);
	scanf("%s",s);
	len=strlen(s);
	p[0]=fac[0]=1;
	for (i=1;i<=100000;i++) {
		p[i]=(p[i-1]*i)%mod;fac[i]=fac[i-1]*25;
		fac[i]%=mod;
	}
	inv[100000]=fastpow(p[100000],mod-2);  
    for (i=99999;i>=0;i--) {  
        inv[i]=inv[i+1]*(i+1);  
        inv[i]%=mod;  
    }  
	for (i=1;i<=m;i++) {
		scanf("%d",&t);
		if (t==1) {
			scanf("%s",s);len=strlen(s);
		} else {
			scanf("%I64d",&n);
			v[len].push_back(n);
			d[len].push_back(++c);
			a[len]=max(a[len],n);
		}
	}
	for (i=1;i<=100000;i++) {
		if (v[i].size()) {
			mem0(dp);
			dp[i]=1;
			for (j=i+1;j<=a[i];j++) {
				dp[j]=(26*dp[j-1])%mod+(lucas(j-1,i-1)*fac[j-i])%mod;
				dp[j]%=mod;
			}
			for (j=0;j<v[i].size();j++)
				ans[d[i][j]]=dp[v[i][j]];
		}
	}
	for (i=1;i<=c;i++) printf("%I64d\n",ans[i]);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值