您的位置:首页 > Web前端

Educational Codeforces Round 11 E. Different Subsets For All Tuples 动态规划★ ★

2016-09-15 17:57 441 查看

题意

现在定义f(a)表示这个a串里面所有不相同的子序列的个数
现在给你n,m,让你用字符集为m,去构造出长度为n的串
然后让你算出所有f(a)的累加

题解:

考虑dp
dp[i][j]表示长度为i,以字符j结尾的答案是多少
dp[i][j]=sigma(dp[i-1][k]*2-dp[pre[j]-1][k])
然后这个玩意儿显然对于任意的j的都是一样的,而且pre[j]前面的每个位置都是可能的,这里的dp是个前缀和,所以直接扣除就可以了
那么直接化简为:dp[i]=dp[i-1]*(2m-1)
但是这个dp是没有考虑空串的
那么在加上空串就好了,所以答案就是
dp[i] = dp[i-1]*(2m-1)+m^(i-1)
法二:
强行推公式,枚举长度k,考虑每个长度为k的序列能作为多少个长度为n的序列的子序列,考虑k>=1,记子序列为s[1]s[2]...s[k],位置序列为p[1]p[2]...p[k],为了保证不重不漏,对每个长为n的序列,如果包含s[]作为子序列,找出使得位置序列字典序最小的,这要求p[1]之前不出现s[1],p[1]和p[2]之间不出现s[2],依此类推,枚举最后一个位置q,即q=p[k],那么有C(q-1,k-1)*m^k*(m-1)^(q-k)*m^(n-q),上式对q从k到n,对k从1到n求和,考虑交换求和,先对k从1到q求和,得到m^(n-q+1)*(2m-1)^(q-1),上式对q从1到n求和,这是个等比数列,可以进一步化简,再加上k=0的贡献m^n即可,复杂度O(logn)。

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;

int main()
{
int n,m;
scanf("%d%d",&n,&m);
long long ans = 2*m;
long long tmp = 1;
for(int i=2;i<=n;i++)
{
tmp = tmp * m % mod;
ans = (ans * (2 * m - 1) % mod + tmp + mod) % mod;
}
cout<<ans<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: