2022/04/08 集訓部分題解
阿新 • • 發佈:2022-04-08
因為我太遜了,所以只說一下 T1 吧。
Solution
考慮如何避免算重,你發現我們可以每次變化,如果加1,我們就必須在1的最前面加,加0就在0的最後面加,那麼就是:
- 在最開頭插入一個 1
- 把 0 變為 01
- 把 1 變為 10
- 在最後面插入一個 0
考慮從最終狀態不停逆操作,那麼我們如果最開頭加入一個 0,末尾加入一個 1,那麼就是每次選一個 01,然後留一個。那麼我們考慮加入分隔符,每次刪的時候就把分隔符也刪掉,那麼我們分隔符的刪除順序就可以確定我們的操作順序。
可以發現的是,如果是0,那麼右邊的分隔符刪除時間大於左邊,反之亦反,而這個又是一個充分條件,所以我們可以直接容斥,後面的步驟就和 不等關係 一樣了。
對於 ? ,你發現啥關係都可以,直接隔開就好了。
Code
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 998244353 #define MAXN 250005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} #define poly vector<int> #define SZ(A) ((A).size()) #define MAXX 2000005 int n,fac[MAXN],ifac[MAXN]; int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a); return res; } int binom (int a,int b){return a >= b ? mul (fac[a],mul (ifac[b],ifac[a - b])) : 0;} void Add (int &a,int b){a = add (a,b);} void Sub (int &a,int b){a = dec (a,b);} void putout (poly A){ cout << SZ(A) << ": "; for (Int i = 0;i < SZ(A);++ i) cout << A[i] << " , ";cout << endl; } int rev[MAXX],w[MAXX]; void init_ntt (){ int lim = 1 << 20; for (Int i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 19); int Wn = qkpow (3,(mod - 1) / lim);w[lim >> 1] = 1; for (Int i = lim / 2 + 1;i < lim;++ i) w[i] = mul (w[i - 1],Wn); for (Int i = lim / 2 - 1;i;-- i) w[i] = w[i << 1]; } void ntt (poly &a,int type){ #define G 3 #define Gi 332748118 static int d[MAXX];int lim = a.size(); for (Int i = 0,z = 20 - __builtin_ctz(lim);i < lim;++ i) d[rev[i] >> z] = a[i]; for (Int i = 1;i < lim;i <<= 1) for (Int j = 0;j < lim;j += i << 1) for (Int k = 0;k < i;++ k){ int x = mul (w[i + k],d[i + j + k]); d[i + j + k] = dec (d[j + k],x),d[j + k] = add (d[j + k],x); } for (Int i = 0;i < lim;++ i) a[i] = d[i] % mod; if (type == -1){ reverse (a.begin() + 1,a.begin() + lim); for (Int i = 0,Inv = qkpow (lim,mod - 2);i < lim;++ i) a[i] = mul (a[i],Inv); } #undef G #undef Gi } poly operator * (poly A,poly B){ int lim = 1,l = 0,len = SZ(A) + SZ(B) - 1; while (lim < SZ(A) + SZ(B)) lim <<= 1,++ l; A.resize (lim),B.resize (lim),ntt (A,1),ntt (B,1); for (Int i = 0;i < lim;++ i) A[i] = mul (A[i],B[i]); ntt (A,-1),A.resize (len); return A; } char str[MAXN],st[MAXN]; int cnt,dp[MAXN],pre[MAXN]; void cdq (int l,int r){ if (l == r) return ; int mid = l + r >> 1; cdq (l,mid); poly G1,G2;G1.resize (mid - l + 1),G2.resize (r - l + 1); for (Int i = 0;i <= mid - l;++ i) if (str[l + i] != '<') G1[i] = pre[l + i] & 1 ? (mod - dp[l + i]) : dp[l + i];else G1[i] = 0; for (Int i = 0;i <= r - l;++ i) G2[i] = ifac[i]; G1 = G1 * G2; for (Int i = mid + 1;i <= r;++ i) if (str[i] != '<') Add (dp[i],pre[i] & 1 ? G1[i - l] : (mod - G1[i - l])); cdq (mid + 1,r); } int solveit (){ pre[1] = 1;int N = cnt + 1;str[N] = 0; // for (Int i = 1;i <= cnt;++ i) cout << str[i];cout << endl; for (Int i = 2;i <= N;++ i) pre[i] = pre[i - 1] + (str[i - 1] != '<'); dp[0] = 1,cdq (0,N);int res = mul (dp[N],fac[N]); for (Int i = 0;i <= N;++ i) dp[i] = 0; // cout << N << ": " << res << endl; return res; } signed main(){ freopen ("a.in","r",stdin); freopen ("a.out","w",stdout); init_ntt ();read (n),scanf ("%s",st + 1),++ n; fac[0] = 1;for (Int i = 1;i <= n;++ i) fac[i] = mul (fac[i - 1],i); ifac[n] = qkpow (fac[n],mod - 2);for (Int i = n;i;-- i) ifac[i - 1] = mul (ifac[i],i); int rst = n,ans = 1; for (Int i = 1;i < n;++ i){ if (st[i] == '0') str[++ cnt] = '<'; else if (st[i] == '1') str[++ cnt] = '>'; else ans = mul (ans,mul (binom (rst,cnt + 1),solveit ())),rst -= cnt + 1,cnt = 0; } ans = mul (ans,solveit ()); write (ans),putchar ('\n'); return 0; } /* */