LOJ6497「雅禮集訓 2018 Day1」圖
阿新 • • 發佈:2021-10-08
考慮暴力,設 \(f(i,k,x,y)\) 表示考慮到第 \(i\) 個點,目前有 偶數/奇數 條路徑,已經有 \(x\) 個定為黑色的點有奇數條路徑結尾,有 \(y\) 個定為白色的點有奇數條路徑結尾,的答案
那麼轉移的話,列舉當前點顏色,以白色為例
- 若 \(y=0\),則無論前 \(i\) 個點如何向 \(i+1\) 連,本來白色的無法多形成路徑,本來黑色的沒有,那麼只有一條新增路徑是 \(i+1\) 一個單點有 \(2^i f(i,k,x,0)\rightarrow f(i+1,k\operatorname{xor} 1,x,0)\)
- 若 \(y\neq 0\)
- 但發現這樣 \(f(i,k,x,y)\) 乘的係數都是 \(2^{i-1}\),所以 \(x,y\) 都只要記錄為 \(0\) 或 \(1\) 即可,於是就有了 \(O(n)\) 做法
黑色同理
#define mod 998244353 #define N 200006 int n; long long f[N][2][2][2],power[N];//f[i][k][x][y] k: even/odd x: white y: black inline void add(long long &x,long long y){x=(x+y>=mod)?(x+y-mod):(x+y);} int main(){ n=read();int need=read(); power[0]=1; for(int i=1;i<=n;i++) power[i]=power[i-1]*2%mod; int a=read(); if(a!=1) f[1][1][1][0]=1;//white if(a!=0) f[1][1][0][1]=1;//black for(int i=1;i<n;i++){ a=read(); for(int k=0;k<2;k++)for(int x=0;x<2;x++)for(int y=0;y<2;y++)if(f[i][k][x][y]){ long long now=f[i][k][x][y]; if(a!=1){//i+1: white if(!y) add(f[i+1][k^1][1][y],now*power[i]%mod); else{ add(f[i+1][k][x][y],now*power[i-1]%mod);add(f[i+1][k^1][1][y],now*power[i-1]%mod); } } if(a!=0){//i+1: black if(!x) add(f[i+1][k^1][x][1],now*power[i]%mod); else{ add(f[i+1][k][x][y],now*power[i-1]%mod);add(f[i+1][k^1][x][1],now*power[i-1]%mod); } } } } long long ans=0; for(int x=0;x<2;x++)for(int y=0;y<2;y++) add(ans,f[n][need][x][y]); printf("%lld\n",ans); return 0; }