NOIP 模擬 $88\; \rm 按位或$
阿新 • • 發佈:2021-11-02
題解
題解 \(by\;zj\varphi\)
設 \(t\) 的所有子集中為 \(3\) 的倍數的數的個數為 \(m\) ,那麼總方案數就是 \(m^n\)。
考慮容斥減掉所有不合法的情況,二項式反演推一下:
設 \(f_i\) 為至多有 \(i\) 位為 \(1\),\(g_i\) 表示恰好有 \(i\) 位為 \(1\)(其中 \(i\) 位都是具體的 \(i\) 位,不是單指數量),則有:
\[f_n=\sum_{i=0}^n\binom{n}{i}g_i\\ g_n=\sum_{i=0}^n(-1)^{n-i}\binom{n}{i}f_i \]答案就是 \(g_n\),問題變為如何求 \(f_i\)
一種方案是暴力列舉哪些位為 \(1\),但是複雜度就成了 \(\mathcal{O\rm(n)}\)。
發現每一位 \(\mod 3\) 只可能是 \(2\) 或 \(1\),那麼只需要知道留下的位中有多少個 \(\mod 3\) 為 \(1\) 的,為 \(2\) 的即可。
實現的時候列舉選了多少位,其中多少個為 \(1\) 的,多少個為 \(2\) 的,求方案數用一個揹包,最後乘上組合數。
其實求的不是 \(f_i\),而是 \(\binom{n}{i}f_i\),所以最後直接按著容斥係數加上即可。
複雜度 \(\mathcal{O\rm(log^2t\times logn)}\)。
Code
#include<bits/stdc++.h> #define ri signed #define pd(i) ++i #define bq(i) --i #define func(x) std::function<x> namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++ #define debug1(x) std::cerr << #x"=" << x << ' ' #define debug2(x) std::cerr << #x"=" << x << std::endl #define Debug(x) assert(x) struct nanfeng_stream{ template<typename T>inline nanfeng_stream &operator>>(T &x) { bool f=false;x=0;char ch=gc(); while(!isdigit(ch)) f|=ch=='-',ch=gc(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc(); return x=f?-x:x,*this; } }cin; } using IO::cin; namespace nanfeng{ #define FI FILE *IN #define FO FILE *OUT template<typename T>inline T cmax(T x,T y) {return x>y?x:y;} template<typename T>inline T cmin(T x,T y) {return x>y?y:x;} using ll=long long; static const int MOD=998244353; int C[65][65],nm,nm1,nm2; ll dp[2][3],n,t,ans; auto fpow=[](ll x,int y) { ll res=1; while(y) { if (y&1) res=res*x%MOD; x=x*x%MOD; y>>=1; } return res; }; auto calc=[](int a,int b) { memset(dp,0,sizeof(dp)); int nw=0; dp[0][0]=1; for (ri i(1);i<=a;pd(i)) { int cur=nw^1; memcpy(dp[cur],dp[nw],sizeof(dp[nw])); for (ri j(0);j<3;pd(j)) (dp[cur][(j+1)%3]+=dp[nw][j])%=MOD; nw=cur; } for (ri i(1);i<=b;pd(i)) { int cur=nw^1; memcpy(dp[cur],dp[nw],sizeof(dp[nw])); for (ri j(0);j<3;pd(j)) (dp[cur][(j+2)%3]+=dp[nw][j])%=MOD; nw=cur; } return dp[nw][0]; }; inline int main() { FI=freopen("or.in","r",stdin); FO=freopen("or.out","w",stdout); cin >> n >> t; C[0][0]=1; for (ri i(1);i<=60;pd(i)) { C[i][0]=1; for (ri j(1);j<=60;pd(j)) C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD; } for (ri i(0);i<=60;pd(i)) if (t>>i&1ll) { ++nm; if (i&1) ++nm2;else ++nm1; } int ln=n%(MOD-1); for (ri i(0),f(1);i<=nm;pd(i),f=-f) { int lim=cmin(i,nm1); for (ri j(0);j<=lim;pd(j)) { if (i-j>nm2) continue; ans+=f*fpow(calc(nm1-j,nm2-i+j),ln)*C[nm1][j]%MOD*C[nm2][i-j]%MOD; } } printf("%lld\n",(ans%MOD+MOD)%MOD); return 0; } } int main() {return nanfeng::main();}