200720-NOIP基础测试 字符串操作(组合数学)

这是今天基础(并不)测试的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+mi1个,原串除掉第一个还有 m − 1 m-1 m1个,所以原串的排列情况就是 C n + m − i − 1 m − 1 C^{m-1}_{n+m-i-1} Cn+mi1m1
最后,我们考虑后面插入的字母,共 n − i n-i ni个,由于我们要保证我们钦定的原串一定要在最后,所以每个蓝色区域内都不能选择与它前面一个原串的字母相同的字母,所以只有25种选择,一共有 2 5 n − i 25^{n-i} 25ni种。
好了,我们终于把每个部分的情况讨论完了,最后只需要将它们乘起来就可以了。

#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!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值