【BZOJ4903】【CTSC2017】吉夫特 [DP]
吉夫特
Time Limit: 15 Sec Memory Limit: 512 MB[Submit][Status][Discuss]
Description
Input
第一行一个整数n。
接下来n行,每行一个整数,这n行中的第i行,表示ai。
Output
一行一个整数表示答案。
Sample Input
4
15
7
3
1
15
7
3
1
Sample Output
11
HINT
Main idea
给定一个序列,问有多少个子序列满足相邻的数构成的组合数都为奇数。
Solution
首先我们用Lucas定理推一推可以知道:C(n,m)为奇数当且仅当n&m=m。
有了这个定理就好办了,我们可以显然地想到DP:通过枚举数在二进制下的子集转移,这样保证了可以转移过去。
由于序列每个数都不同,且最大值为233333,所以效率是O(3^18)的。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 using namespace std; 9 10 const int ONE = 300005; 11 const int MOD = 1e9+7; 12 13 int n,x; 14 int f[ONE]; 15 int Ans; 16 17 int get() 18 { 19 int res=1,Q=1;char c; 20 while( (c=getchar())<48 || c>57 ) 21 if(c=='-')Q=-1; 22 res=c-48; 23 while( (c=getchar())>=48 && c<=57 ) 24 res=res*10+c-48; 25 return res*Q; 26 } 27 28 int main() 29 { 30 n = get(); 31 for(int i=1; i<=n; i++) 32 { 33 x = get(); 34 int record = (f[x] + 1) % MOD; 35 for(int sub=x; sub; sub=(sub-1) & x) 36 f[sub] = (f[sub] + record) % MOD; 37 Ans = (Ans + record) % MOD; 38 } 39 printf("%d", Ans-n); 40 }