这是今天基础(并不)测试的T3…顺便去学了一下乘法逆元… …
题意:给定一个字符串S和一个整数k,要求用任意一个小写字母插入S中的任意位置,重复k次,求能构成多少个不同的字符串。(答案对 1 e 9 + 7 1e9+7 1e9+7取模)
这里画了一张草图。
设原串长为
m
m
m,插入
n
n
n个字母,插完后总长度为
n
+
m
n+m
n+m。
首先我们钦定最后一次出现的原串为原串,举个例子:S为
o
o
f
oof
oof,插入后为
o
o
f
o
o
f
f
oofooff
oofooff,则第3、4个
o
o
o和最后一个
f
f
f为S。
然后我们枚举原串第一个字母出现的位置
i
+
1
i+1
i+1,则它前面就插了
i
i
i个字母,这
i
i
i个字母可以随便选,所以。一共有
2
6
i
26^i
26i种。
然后我们考虑后面的情况,后面总共有
n
+
m
−
i
−
1
n+m-i-1
n+m−i−1个,原串除掉第一个还有
m
−
1
m-1
m−1个,所以原串的排列情况就是
C
n
+
m
−
i
−
1
m
−
1
C^{m-1}_{n+m-i-1}
Cn+m−i−1m−1。
最后,我们考虑后面插入的字母,共
n
−
i
n-i
n−i个,由于我们要保证我们钦定的原串一定要在最后,所以每个蓝色区域内都不能选择与它前面一个原串的字母相同的字母,所以只有25种选择,一共有
2
5
n
−
i
25^{n-i}
25n−i种。
好了,我们终于把每个部分的情况讨论完了,最后只需要将它们乘起来就可以了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
int n,m;
ll ans,f[2000005],inv[2000005];
char s[1000005];
ll qp(ll x,ll y) //快速幂
{
ll res=1;
while(y)
{
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res%mod;
}
void init()
{
f[0]=1;
for(int i=1;i<=n+m;i++)
f[i]=f[i-1]*i%mod; //阶乘
inv[n+m]=qp(f[n+m],mod-2);
for(int i=n+m-1;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod; //阶乘的逆元
}
ll C(int x,int y)
{
return f[y]*inv[x]%mod*inv[y-x]%mod;
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%d%s",&n,s);
m=strlen(s);
init();
for(int i=0;i<=n;i++)
ans=(ans+qp(26,i)*C(m-1,n+m-i-1)%mod*qp(25,n-i)%mod)%mod;
printf("%lld",ans);
return 0;
}
最后注意开 l o n g long long l o n g long long!!!