题解:P11326 【MX-S7-T4】「SMOI-R2」XA-Game
posted on 2025-01-01 10:50:57 | under | source
larsr 出的妙妙题。
要计数先判定。考察本题中两人操作的性质:
- Alice 无论怎么操作,无法改变 \(1\) 的数量的奇偶性。
- 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;
}

浙公网安备 33010602011771号