1. 程式人生 > >洛谷3773 BZOJ4903 CTSC2017 吉夫特 數學 dp

洛谷3773 BZOJ4903 CTSC2017 吉夫特 數學 dp

題目連結 題意: 給你一個單調不升的陣列a,求有多少個長度大於等於2的子序列滿足i=2kCbibi1mod  2=1\prod_{i=2}^kC_{b_i}^{b_{i-1}}\mod 2=1。答案對1000000007取模。

題解: 首先題意是讓你求一個相鄰兩數組合數膜2意義下都是1的子序列,也就是要求相鄰兩數組合數是奇數。我們考慮對於一個組合數Cnm=n!m!(nm)!C_n^m=\frac{n!}{m!(n-m)!},如果它是個奇數,意味著我們能從n!n!中提取的因子2的個數和從m

!(nm)!m!(n-m)!中提取的因子2的個數相同。 根據組合數取模的盧卡斯定理,我們有Cnm%2=Cn%2m%2Cn/2m/2C_{n}^{m} \% 2=C_{n\%2}^{m\%2}*C_{n/2}^{m/2}。我們可以看出,這個式子相當於在對n和m進行二進位制分解,從二進位制的最低位到最高位依次判斷n和m在該位對應的01,我們發現,如果在某一位n=0,m=1,那麼C01C_0^1是不存在方案的,看作結果是0,不管其他位結果如何,答案在乘0之後肯定會變成0,所以我們可以推出,如果想要Cnm%2=1C_n^m\%2=1,那麼需要滿足的條件就是二進位制下n的每一個是1的位,m對應位可以是1也可以是0,n是0的位,m對應位也一定要是0,也就是n
&m=mn\&m=m
。如果像狀壓dp那樣把一個二進位制下的01串看作一個集合,那麼m&m=mm\&m=m就相當於要求m在二進位制下是n的一個子集。 那麼我們考慮dp,設dp[i]為數字i結尾的方案數,那麼這個狀態可以轉移到所有i的二進位制數的子集。最後對於每一個在aia_i中出現的數,它的初值設為1,最後對答案的貢獻要減1,相當於減去了長度為1只有aia_i本身的子序列。 程式碼很短:

#include <bits/stdc++.h>
using namespace std;
int n,tong[300010],a[300010]; int dp[300010],ans; const int mod=1000000007; int main() { scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); tong[a[i]]=i; dp[a[i]]=1; } for(int i=1;i<=n;++i) { for(int j=(a[i]-1)&a[i];j;j=(j-1)&a[i]) { if(tong[j]>i) dp[j]=(dp[j]+dp[a[i]])%mod; } } for(int i=1;i<=n;++i) ans=(ans+dp[a[i]]-1)%mod; printf("%d\n",ans); return 0; }