習題:Felicity's Big Secret Revealed(狀壓DP)
阿新 • • 發佈:2020-08-09
題目
思路
經過打表可以發現,出現的最大值最大隻能為20,
我們設\(dp[i][j]\)表示最後一刀切在i和i+1之間,已經有的狀態為j
轉移的話暴力列舉接下來的一個區間即可
考慮到要捨去第一刀前面的內容,所以對於所有的\(dp[i][0]\)都要賦上1的初值
最後的答案即為\(\sum_{i=1}^{n}\sum_{j=1}^{20}dp[i][j]\)
程式碼
#include<iostream> using namespace std; const int mod=1e9+7; int dp[76][(1<<20)],ans; int n; int a[76]; char s[76]; void divide(int val) { if(val==0) cout<<'0'; while(val) { cout<<(val&1); val>>=1; } } int main() { ios::sync_with_stdio(false); cin>>n; cin>>(s+1); for(int i=1;i<=n;i++) { a[i]=s[i]-'0'; dp[i][0]=1; } dp[0][0]=1; for(int i=0;i<=n;i++) { for(int j=0;j<(1<<20);j++) { int now=0; for(int k=i+1;k<=n;k++) { now=(now<<1)+a[k]; if(now==0) continue; if(now>20) break; dp[k][j|(1<<(now-1))]=(dp[k][j|(1<<(now-1))]+dp[i][j])%mod; } } } for(int i=1;i<=n;i++) for(int j=1;j<=20;j++) ans=(ans+dp[i][(1<<j)-1])%mod; cout<<ans; return 0; }