Luogu P4996 咕咕咕
阿新 • • 發佈:2018-11-08
題目名字真是十分契合Luogu的性質啊
IG NB
\(3^n\)的子集列舉不會……看了題解後只會正解
對於每個狀態,其實對我們有用的只有這個狀態中有多少個\(1\),而\(1\)的位置我們並不關心,因為具有相同個數個\(1\)的狀態,它們出現的次數一定是相同的。
所以我們考慮用dp[i]
表示有\(i\)個\(1\)的方案數,因為我們可以一步一步的填\(1\),所以dp[i]=dp[i]+dp[i-j]*c[i][j]
,其中c[i][j]
表示\(C^j_i\),即\(dp[i]=\sum\limits_{j=1}^{i} dp[i-j] \cdot C^j_i\)
有了上面的式子,我們預處理組合數和\(dp[i]\)
一定要多取模,不然會炸。 十年OI一場空,忘掉取模見祖宗
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mod 998244353 #define LL long long using namespace std; LL c[30][30]; LL dp[30]; void init(){ c[0][0]=1; for(int i=1;i<=20;i++) c[i][0]=1; for(int i=1;i<=20;i++) for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; dp[0]=1; for(int i=1;i<=20;i++) for(int j=1;j<=i;j++) dp[i]=(dp[i]+(dp[i-j]*c[i][j])%mod)%mod; } int read(){ char c=getchar(); while(c<'0'||c>'9') c=getchar(); return c-48; } LL cnt,ans; int main(){ init(); int n,m; cin>>n>>m; for(int i=1;i<=m;i++){ cnt=0; for(int j=1;j<=n;j++) if(read()) cnt++; LL k; cin>>k; ans=(ans+(((k*dp[cnt])%mod)*dp[n-cnt])%mod)%mod; } cout<<ans; return 0; }