题解:P11326 【MX-S7-T4】「SMOI-R2」XA-Game

posted on 2025-01-01 10:50:57 | under | source

larsr 出的妙妙题。

要计数先判定。考察本题中两人操作的性质:

  1. Alice 无论怎么操作,无法改变 \(1\) 的数量的奇偶性。
  2. Bob 操作会改变其奇偶性。但是对两个 \(0\) 操作则不会改变奇偶性,有点类似于交换先后手。

当序列中不存在 \(00\) 子串时,Alice 必然可以操作使得留给 Bob 的局面仍不存在 \(00\) 子串(优先操作 \(01\)\(10\),假如都是 \(1\) 那也只会产生一个 \(0\))。这种局面下,Bob 至多产生一个 \(00\) 子串,但是 Alice 也可以将其消掉。那么 Bob 无法改变结果。

于是得出获胜充分条件:至多存在一个 \(00\) 子串,且 \(1\) 的数量奇偶性与 Bob 操作次数即 \(\lfloor\frac{n-1}2\rfloor\) 不同。

现在证明它是必要条件:

  • 假如 \(1\) 数量奇偶性与其相同,Bob 维持现状不对 \(00\) 操作即可,除非全是 \(0\),但此时 Alice 必输。
  • 否则,假如存在两个 \(00\) 子串,那么 Bob 对其一操作后即可“交换先后手”,根据上一条的说明此时 Alice 必败。

对符合条件的序列计数,大力 dp 即可。\(n\) 比较大,所以需要矩阵快速幂优化。但是邪恶的 larsr 还把普通快速幂卡掉了,可以借鉴光速幂的思想。最后,向量乘矩阵只需枚举一维,能有效优化常数。

单次复杂度 \(O(L^2m)\),其中 \(L\) 为矩阵大小,此题 \(L=8\)

代码

#include<bits/stdc++.h>
#pragma GCC optimize(3, "Ofast", "inline")
using namespace std;

#define ADD(a, b) a = (a + b) % mod 
#define LL long long
const int N = 5e5 + 5, M = 8, mod = 1e9 + 7, BAS = 1e5;
int T, m, v[N], mul, c[M];
LL n, a[N];

struct Matrix{
	int a[M][M];
	inline Matrix () {memset(a, 0, sizeof a);}
	inline Matrix operator * (const Matrix &B) const{
		Matrix C;
		for(int i = 0; i < M; ++i)
			for(int j = 0; j < M; ++j)
				for(int k = 0; k < M; ++k)
					ADD(C.a[i][j], 1ll * a[i][k] * B.a[k][j] % mod);
		return C;
	}
} I, M0, M1, M2, ANS;

inline void MUL(const Matrix &B){
	memset(c, 0, sizeof c);
	for(int j = 0; j < M; ++j)
		for(int k = 0; k < M; ++k)
			ADD(c[j], 1ll * ANS.a[0][k] * B.a[k][j] % mod);
	for(int j = 0; j < M; ++j) ANS.a[0][j] = c[j];
}

namespace VeryFastPow{
	Matrix Mul[3][BAS + 5];
	inline void init(){
		for(int i = 0; i < 3; ++i){
			Matrix MM = (!i ? M2 : Mul[i - 1][BAS]);
			Mul[i][0] = I; 
			for(int j = 1; j <= BAS; ++j) Mul[i][j] = Mul[i][j - 1] * MM; 
		}
	} 
	inline void qstp(LL k){
		if(k % BAS) MUL(Mul[0][k % BAS]);
		if((k / BAS) % BAS) MUL(Mul[1][(k / BAS) % BAS]);
		if(k / BAS / BAS) MUL(Mul[2][k / BAS / BAS]);
	}
};

inline int id(int a, int b, int c) {return a * 4 + b * 2 + c;}
inline void init(){
	for(int i = 0; i < M; ++i) I.a[i][i] = 1;
	for(int i = 0; i < 2; ++i)
		for(int j = 0; j < 2; ++j)
			for(int k = 0; k < 2; ++k){
				// 0
				if(!j || i) ++M0.a[id(i, j, k)][id(0, j | (i == 0), k)];
				// 1
				++M1.a[id(i, j, k)][id(1, j, k ^ 1)];
			}
	for(int i = 0; i < M; ++i)
		for(int j = 0; j < M; ++j)
			M2.a[i][j] = M1.a[i][j] + M0.a[i][j];
}
signed main(){
	init(), VeryFastPow::init();
	
	cin >> T;
	while(T--){
		scanf("%lld%d", &n, &m), mul = 1;
		for(int i = 1; i <= m; ++i) mul = 2ll * mul % mod, scanf("%lld%d", &a[i], &v[i]);
		
		for(int i = 0; i < 8; ++i) ANS.a[0][i] = 0;
		ANS.a[0][id(1, 0, 0)] = true; 
		for(int i = 1; i <= m; ++i) VeryFastPow::qstp(a[i] - a[i - 1] - 1), MUL(v[i] ? M1 : M0);	 
		VeryFastPow::qstp(n - a[m]);
		
		int ans = 0;
		for(int i = 0; i < 2; ++i)
			for(int j = 0; j < 2; ++j)
				ADD(ans, ANS.a[0][id(i, j, (((n - 1) / 2) & 1) ^ 1)]);
		printf("%d\n", 1ll * ans * mul % mod);		
	}
	return 0;
}
posted @ 2026-01-15 08:19  Zwi  阅读(3)  评论(0)    收藏  举报