【2021寒假集训营第一场】A-串
dp,容斥原理,快速幂
这个题目就是容斥原理的应用,关键是弄明白长度为i的字符串根据us分为几种
长度为i的字符串主要分为三种:
- 不含u的
- 含u不含us的
- 含us的
这三种加起来就是全集
解法一:
使用(f[i])表示长度为i的含有us的字符串
可以分为以下两种:
- 前i-1个字符串含有us,那么第i个字符可以是26个字母中任意一个:(f[i] += f[i-1]*26)
- 前i-1个字符含有u,但是不含有us,那么第i个字符只需要填一个i即可:(f[i] += 26^{i-1} -25^{i-1} - f[i-1])
- 前i-1个字符含有u(即全部组合减去不含有u的组合):(26^{i-1} -25^{i-1})
- 不含有us,上面的结果减去含有us的即可,(26^{i-1} -25^{i-1}-f[i-1])
所以结果就是(f[i] = 26^{i-1} -25^{i-1} + 25* f[i-1])
注意这里计算幂的时候要使用到快速幂算法,其中还需要取模运算
ac代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
int n;
ll f[2000010];
int q_pow(ll a, ll n)
{
ll ans = 1;
ll tot = a; // 这里必须是ll类型,不然就会出错!因为tot是指数上升的
while(n){
if(n&1) ans = (ans*tot)%mod;
tot = (tot*tot)%mod;
n>>=1;
}
return ans%mod;
}
int main()
{
cin >> n;
f[2] = 1;
for(int i=3; i<=n; ++i){
f[i] = (q_pow(26, i-1) - q_pow(25, i-1) + f[i-1]*25 % mod + mod)%mod; // 括号里面+mod是为了防止负数
}
ll ans = 0;
for(int i=2; i<=n; ++i){
ans = (ans+f[i])%mod;
}
printf("%lld
", ans);
return 0;
}
解法二:
将一个长为i的字符串分为三类,并用(f[i][0/1/2])表示
- (f[i][0])表示的是长度为i,不含有u的字符串
- (f[i][1])表示的是长度为i,含有u,不含有us的字符串
- (f[i][2])表示的是含有us的字符串
则可以得到以下关系:
- (f[i][0] = 25*f[i-1][0]);即前i个不含有u的字符串为前i-1个不含u的字符串,末尾添加一个非u字符
- (f[i][1] = f[i-1][0] + f[i-1][1]*25);如1,根据公式理解即可
- (f[i][2] = f[i-1][1] + f[i-1][2]*26);如1,根据公式理解即可
ac 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
int n;
ll f[1000010][3];
int main()
{
cin >> n;
f[2][0] = 25*25;
f[2][1] = 50;
f[2][2] = 1;
for(int i=3; i<=n; ++i){
f[i][0] = f[i-1][0]*25%mod;
f[i][1] = (f[i-1][0] + 25*f[i-1][1])%mod;
f[i][2] = (f[i-1][1] + 26*f[i-1][2])%mod;
}
ll ans = 0;
for(int i=2; i<=n; ++i){
ans = (ans+f[i][2])%mod;
}
cout << ans;
return 0;
}