首页 > 代码库 > cf660E Different Subsets For All Tuples
cf660E Different Subsets For All Tuples
For a sequence a of n integers between 1 and m, inclusive, denote f(a) as the number of distinct subsequences of a (including the empty subsequence).
You are given two positive integers n and m. Let S be the set of all sequences of length n consisting of numbers from 1 to m. Compute the sum f(a) over all a in S modulo 109?+?7.
The only line contains two integers n and m (1?≤?n,?m?≤?106) — the number of elements in arrays and the upper bound for elements.
Print the only integer c — the desired sum modulo 109?+?7.
1 3
6
2 2
14
3 3
174
数论题都是一生之敌QAQ
看了一遍官方tutorial没怎么懂,搜题解的时候突然看见Q神orz
“E题,强行推公式,枚举长度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)。”——by Q神
空集单独考虑,就最后加上个m^n就行
枚举一个长度len的子序列,假设是x[1]x[2]...x[len],考虑有多少个长度为n的串出现过这个子序列
为了统计不重不漏,只考虑这个子序列第一次出现在这个串中
因为是第一次出现,那么在x[1]之前不能有x[1]同样的,x[1]和x[2]之间不能有x[2]同样的,,,以此类推
所以在x[k]之前其他未定的位置都恰好有(m-1)种取法
x[len]之后就随意了,因为怎么取都不影响x[1]x[2]...x[len]子序列第一个出现,所以都有m种取法
而每个x[i]都有m种取法,
假设最后一个x[len]出现在q位置,前面x[1]~x[len-1]有C(q-1,len-1)种放法
最后答案是C(q-1,len-1)*m^len*(m-1)^(q-len)*m^(n-q)
瞎鸡儿一通化简之后
Σm^(n-len+1)*(2m-1)^(len-1)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<deque> 9 #include<set> 10 #include<map> 11 #include<ctime> 12 #define LL long long 13 #define inf 0x7ffffff 14 #define pa pair<int,int> 15 #define mkp(a,b) make_pair(a,b) 16 #define pi 3.1415926535897932384626433832795028841971 17 #define mod 1000000007 18 using namespace std; 19 inline LL read() 20 { 21 LL x=0,f=1;char ch=getchar(); 22 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 23 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 24 return x*f; 25 } 26 LL n,m; 27 inline LL quickpow(LL a,LL b) 28 { 29 LL s=1; 30 while (b) 31 { 32 if (b&1)s=(s*a)%mod; 33 a=(a*a)%mod; 34 b>>=1; 35 } 36 return s; 37 } 38 int main() 39 { 40 n=read();m=read(); 41 LL ans=quickpow(m,n); 42 for (int i=1;i<=n;i++) 43 { 44 ans=(ans+quickpow(m,n-i+1)*quickpow(2*m-1,i-1))%mod; 45 } 46 printf("%lld\n",ans); 47 }
cf660E Different Subsets For All Tuples