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

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

【题目链接】

【思路要点】

  • Matrix67Matrix67 一篇关于 surreal numbersurreal\ number 的博客
  • 考虑用 surreal numbersurreal\ number 解决不平等博弈问题。
  • 手动绘制转移图,计算出各个状态的 surreal numbersurreal\ number ,如下图。
  • image
  • ={00},={0},={0}*=\{0|0\},\uparrow=\{0|*\},\downarrow=\{*|0\} ,实际上这也是 On Numbers and GamesOn\ Numbers\ and\ Games 一文中 ConwayConway 所建议的表示方式。
  • 有如下事实,可由 surreal numbersurreal\ number 的运算方式简单验证:
    11+=0*+*=0
    22 、 令 x>0x>0 ,那么 +x>0*+x>0
    33 、 令 x<0x<0 ,那么 +x<0*+x<0
    44>0,<0\uparrow>0,\downarrow<0
    55+=0\uparrow+\downarrow=0
    66 、 令 x>0x>0 ,那么 +x>0,+x>0\uparrow+x>0,\downarrow+x>0
    77 、 令 x<0x<0 ,那么 +x<0,+x<0\uparrow+x<0,\downarrow+x<0
    88+,+*+\uparrow,*+\downarrow 为先手必胜态。
    99++>0,++<0*+\uparrow+\uparrow>0,*+\downarrow+\downarrow<0
  • 因此结论如下:
  • image
  • 接下来唯一的问题是我们需要解决 number>0,=0,<0\sum number>0,=0,<0 的方案数。
  • (x+1)p(x1+1)q(x+1)^p(x^{-1}+1)^qxix^i 的系数应当为 (p+qi+q)\binom{p+q}{i+q} ,因此我们本质上只需要求出 O(1)O(1)(x+1)p(x2+1)q(x+1)^p(x^2+1)^q 的系数的前缀和,枚举 (x+1)p(x+1)^p 的一项,将 (x2+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;
}
阅读更多
换一批

没有更多推荐了,返回首页