Live2D

2022/04/08 集训部分题解

link

因为我太逊了,所以只说一下 T1 吧。

Solution

考虑如何避免算重,你发现我们可以每次变化,如果加1,我们就必须在1的最前面加,加0就在0的最后面加,那么就是:

  1. 在最开头插入一个 1
  2. 把 0 变为 01
  3. 把 1 变为 10
  4. 在最后面插入一个 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;
}
/*

*/
posted @ 2022-04-08 18:58  Dark_Romance  阅读(48)  评论(0编辑  收藏  举报