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;
}
/*
*/