【LOJ2327】「清华集训 2017」福若格斯

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/83025412

【题目链接】

【思路要点】

  • M a t r i x 67 Matrix67 一篇关于 s u r r e a l   n u m b e r surreal\ number 的博客
  • 考虑用 s u r r e a l   n u m b e r surreal\ number 解决不平等博弈问题。
  • 手动绘制转移图,计算出各个状态的 s u r r e a l   n u m b e r surreal\ number ,如下图。
  • image
  • = { 0 0 } , = { 0 } , = { 0 } *=\{0|0\},\uparrow=\{0|*\},\downarrow=\{*|0\} ,实际上这也是 O n   N u m b e r s   a n d   G a m e s On\ Numbers\ and\ Games 一文中 C o n w a y Conway 所建议的表示方式。
  • 有如下事实,可由 s u r r e a l   n u m b e r surreal\ number 的运算方式简单验证:
    1 1 + = 0 *+*=0
    2 2 、 令 x > 0 x>0 ,那么 + x > 0 *+x>0
    3 3 、 令 x < 0 x<0 ,那么 + x < 0 *+x<0
    4 4 > 0 , < 0 \uparrow>0,\downarrow<0
    5 5 + = 0 \uparrow+\downarrow=0
    6 6 、 令 x > 0 x>0 ,那么 + x > 0 , + x > 0 \uparrow+x>0,\downarrow+x>0
    7 7 、 令 x < 0 x<0 ,那么 + x < 0 , + x < 0 \uparrow+x<0,\downarrow+x<0
    8 8 + , + *+\uparrow,*+\downarrow 为先手必胜态。
    9 9 + + > 0 , + + < 0 *+\uparrow+\uparrow>0,*+\downarrow+\downarrow<0
  • 因此结论如下:
  • image
  • 接下来唯一的问题是我们需要解决 n u m b e r > 0 , = 0 , < 0 \sum number>0,=0,<0 的方案数。
  • ( x + 1 ) p ( x 1 + 1 ) q (x+1)^p(x^{-1}+1)^q x i x^i 的系数应当为 ( p + q i + q ) \binom{p+q}{i+q} ,因此我们本质上只需要求出 O ( 1 ) O(1) ( x + 1 ) p ( x 2 + 1 ) q (x+1)^p(x^2+1)^q 的系数的前缀和,枚举 ( x + 1 ) p (x+1)^p 的一项,将 ( x 2 + 1 ) q (x^2+1)^q 的系数前缀和即可。
  • 时间复杂度 O ( m ) O(\sum m)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
const int P = 998244353;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int fac[MAXN], inv[MAXN], bit[MAXN];
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
int getc(int x, int y) {
	if (y > x) return 0;
	else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P;
}
void init(int n) {
	fac[0] = bit[0] = 1;
	for (int i = 1; i <= n; i++) {
		fac[i] = 1ll * fac[i - 1] * i % P;
		bit[i] = bit[i - 1] * 2 % P;
	}
	inv[n] = power(fac[n], P - 2);
	for (int i = n - 1; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1ll) % P;
}
int n, m, cnt[8];
//0 : -1, 1 : -1/2, 2 : 0, 3 : 1/2, 4 : 1;
//5 : *, 6 : up, 7 : down.
void Loadinput() {
	read(n), m = 0;
	memset(cnt, 0, sizeof(cnt));
	for (int i = 1; i <= n; i++) {
		string opt; int x;
		cin >> opt >> x; m += x;
		if (opt == "LL_RR") cnt[5] += x;
		if (opt == "L_LRR") cnt[6] += x;
		if (opt == "LLR_R") cnt[7] += x;
		if (opt == "_LLRR") cnt[2] += x;
		if (opt == "LRL_R") cnt[5] += x;
		if (opt == "L_RLR") cnt[5] += x;
		if (opt == "LLRR_") cnt[2] += x;
		if (opt == "LR_LR") cnt[2] += x;
		if (opt == "LRLR_") cnt[2] += x;
		if (opt == "_LRLR") cnt[2] += x;
		if (opt == "_RLLR") cnt[0] += x;
		if (opt == "LRRL_") cnt[4] += x;
		if (opt == "LR_RL") cnt[1] += x;
		if (opt == "RL_LR") cnt[3] += x;
		if (opt == "_RLRL") cnt[0] += x;
		if (opt == "LRR_L") cnt[2] += x;
		if (opt == "R_LLR") cnt[2] += x;
		if (opt == "RLRL_") cnt[4] += x;
		if (opt == "R_LRL") cnt[2] += x;
		if (opt == "RLR_L") cnt[2] += x;
		if (opt == "RRL_L") cnt[4] += x;
		if (opt == "R_RLL") cnt[0] += x;
		if (opt == "RR_LL") cnt[2] += x;
	}
}
int a[MAXN], b[MAXN], c[MAXN], sum[MAXN];
void work(int x, int y, int *a) {
	for (int i = 0; i <= x + y; i++)
		a[i] = getc(x + y, i);
}
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
int main() {
	init(1e6); int T, num;
	read(num), read(T);
	while (T--) {
		Loadinput();
		int num[3] = {0, 0, 0};
		// 0 : negative, 1 : zero, 2 : positive.
		work(cnt[0], cnt[4], a);
		work(cnt[1], cnt[3], b);
		work(cnt[7], cnt[6], c);
		for (int i = 1; i <= cnt[1] + cnt[3]; i++)
			update(b[i], b[i - 1]);
		num[2] = power(2, cnt[0] + cnt[1] + cnt[2] + cnt[3] + cnt[4]);
		for (int i = 0, j = cnt[1] + cnt[3], k = cnt[1] + cnt[3]; i <= cnt[0] + cnt[4]; i++) {
			while (j >= 0 && (i - cnt[0]) * 2 + (j - cnt[1]) >= 0) j--;
			while (k >= 0 && (i - cnt[0]) * 2 + (k - cnt[1]) > 0) k--;
			if (j >= 0) update(num[0], 1ll * a[i] * b[j] % P);
			if (k >= 0) update(num[1], 1ll * a[i] * b[k] % P);
		}
		num[0] = 1ll * num[0] * power(2, cnt[2]) % P;
		num[1] = 1ll * num[1] * power(2, cnt[2]) % P;
		update(num[2], P - num[1]);
		update(num[1], P - num[0]);
		int updown[5] = {0, 0, 0, 0, 0};
		// 0 : less, 1 : -1, 2 : 0, 3 : 1, 4 : more.
		for (int i = 0; i <= cnt[6] + cnt[7]; i++) {
			int tmp = i - cnt[7];
			if (tmp <= -2) update(updown[0], c[i]);
			if (tmp == -1) update(updown[1], c[i]);
			if (tmp == 0) update(updown[2], c[i]);
			if (tmp == 1) update(updown[3], c[i]);
			if (tmp >= 2) update(updown[4], c[i]);
		}
		int ans[4] = {0, 0, 0, 0};
		ans[0] = 1ll * num[2] * power(2, cnt[5] + cnt[6] + cnt[7]) % P;
		ans[1] = 1ll * num[0] * power(2, cnt[5] + cnt[6] + cnt[7]) % P;
		if (cnt[5] == 0) {
			update(ans[0], 1ll * num[1] * (updown[3] + updown[4]) % P);
			update(ans[1], 1ll * num[1] * (updown[0] + updown[1]) % P);
			update(ans[3], 1ll * num[1] * updown[2] % P);
		} else {
			int tmp = power(2, cnt[5] - 1);
			update(ans[0], 1ll * tmp * num[1] % P * (updown[3] + updown[4]) % P);
			update(ans[1], 1ll * tmp * num[1] % P * (updown[0] + updown[1]) % P);
			update(ans[3], 1ll * tmp * num[1] % P * updown[2] % P);
			update(ans[0], 1ll * tmp * num[1] % P * updown[4] % P);
			update(ans[1], 1ll * tmp * num[1] % P * updown[0] % P);
			update(ans[2], 1ll * tmp * num[1] % P * (0ll + updown[1] + updown[2] + updown[3]) % P);
		}
		printf("%d %d %d %d\n", ans[0], ans[1], ans[2], ans[3]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/83025412
今日推荐