1. 程式人生 > 實用技巧 >「CTSC2017」吉夫特【Lucas 定理】【狀壓DP】

「CTSC2017」吉夫特【Lucas 定理】【狀壓DP】

傳送門

solution

\(Lucas\)定理:

\[\binom xy\equiv\binom{x\%2}{y\%2}\binom{x/2}{y/2}\pmod 2 \]

也就相當於設\(x_i,y_i\)分別是\(x,y\)二進位制下的第\(i\)

那麼:

\[\binom xy\equiv\prod_{i}\binom{x_i}{y_i}\pmod 2 \]

因為\(x_i,y_i\in{{0,1}}\),所以只有\(\binom{x_i}{y_i}\)的取值中只有\(\binom 01\)是等於\(0\)的,故

\[\binom {a_{b_{i-1}}}{a_{b_i}}\not =0 \]

意味著二進位制下\(a_{b_i}\)

的每一位都\(\le a_{b_{i-1}}\),將\(a_i\)看作是二進位制下每一個\(1\)組成的集合,那麼\(a_{b_i}\)必須是\(a_{b_{i-1}}\)的子集,因此我們直接設\(dp_i\)表示以\(i\)結尾的長度超過\(1\)的符合條件的子序列的個數,然後列舉\(i\)的子集轉移即可:

code

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=(1<<20)+10;
int n,a[N],f[N],ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		for(int s=(a[i]-1)&a[i];s;s=(s-1)&a[i])
			f[s]=(f[s]+f[a[i]]+1)%mod;
		ans=(ans+f[a[i]])%mod;
	}
	cout<<ans;
	return 0;
}