2021牛客寒假算法基础训练营1补题 - A
题目描述
链接:https://ac.nowcoder.com/acm/contest/9981/A
来源:牛客网
长度不超过nn,且包含子序列“us”的、只由小写字母构成的字符串有多少个? 答案对 10^9+7 取模。
所谓子序列,指一个字符串删除部分字符(也可以不删)得到的字符串。
例如,“unoacscc"包含子序列"us”,但"scscucu"则不包含子序列"us"。
输入描述
一个正整数n (2 <= n <= 1e6)
输出描述
一个正整数,为满足条件的字符串数量对10^9+7取模的值
样例
输入
3
输出
77
说明
长度为3的字符串里,
形状是"u?s"的共有26个
形状是"?us"的共有26个
形状是"us?"的共有26个。
但是,“uss"和"uus"被各多计算了1次,应该减去,
所以共有26*3-2=76个。
再加上长度为2的"us”,所以长度不超过3的合法字符串共有77个
输入
874520
输出
16471619
心路历程
比赛的时候没有做出来,一开始想的是用排列组合的思想,但是会发现有重复的情况,而且重复很难判断有多少个,于是放弃了。赛后看到有用各种dp来写的,本人弱鸡,看的一脸懵逼。晚上ACM集训队大佬分享了一种方法。通过一种找规律的形式,巧妙的AC了,代码量还很少。
规律
把从2 - n长度的字符串的可能性拍成一个三角形,发现如下规律:
所以长度为 L 的字符串数量应该是由长度为 L-1 的字符串数量乘以 26 再加上 (L-1) 个 25 ^ (L-2) 得到,非常巧妙,大佬nb。
代码如下
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
//快速幂
ll power(ll a, ll b)
{
ll ans = 1;
while (b > 0)
{
if (b & 1)
ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
int main()
{
int n;
cin >> n;
ll ans = 1, temp = 1;//temp保存当前长度的字符串总数
for (int i = 1; i < n - 1; i++)
{
temp = temp * 26 % MOD + ((i + 1) % MOD * power(25, i) % MOD) % MOD;
ans = (ans + temp) % MOD;//加上之前的字符串总数得到答案
}
cout << ans;
return 0;
}