XA-Game 题解
现在我们观察一下
-
-
-
0\ 0\rarr 0
-
-
-
0\ 1\rarr 1
-
-
-
1\ 0\rarr 1
-
-
-
1\ 1\rarr 0
-
-
-
-
0\ 0\rarr 0
-
-
-
0\ 1\rarr 0
-
-
-
1\ 0\rarr 0
-
-
-
1\ 1\rarr 1
-
可以发现一些性质:
-
- 除了
[0,0] ,\operatorname{and} 操作完都会使1 的数量减少1 ,也就是说1 的数量的奇偶性会变。
我们现在可以猜想如果每次 dalao 操作序列时都没有
可以知道 dalao 会操作
-
- 最多有一处连续的
0 。
证明完以上的序列成立,我们还要证明不满足以上条件的序列不成立。
如果不满足第一个条件,dalao 可以每次都减少一个
如果满足第一个条件不满足第二个条件,dalao 可以选择一个有一处连续的
证明完以上,问题就变简单了。可以设状态
很明显可以用矩阵乘法加速,复杂度
然后可以利用光速幂的思想优化到
#include<cstdio>
#include<cstring>
#define P 100000
#define N 500010
#define mod 1000000007
#define ll long long
#define zy(a,b,c) ((a)*4+(b)*2+(c))
using namespace std;
ll n, m, a[N], v[N];
struct mat
{
ll a[8][8];
mat operator *(mat x)
{
mat ans;
memset(ans.a, 0, sizeof ans.a);
for(int i = 0; i < 8; i++)
for(int j = 0; j < 8; j++)
for(int k = 0; k < 8; k++)
ans[i][k] = (ans[i][k] + a[i][j] * x[j][k]) % mod;
return ans;
}
ll* operator [](int x)
{
return a[x];
}
};
mat a0, a1, ap, mul[P+10][3], danw;
//last number, sum of number 1 mod 2, number of [0,0]
void init()
{
for(int i = 0; i < 8; i++)danw[i][i] = 1;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
{
if(i || !k)
{
a0[zy(i,j,k)][zy(0,j,k|(!i))] = 1;
ap[zy(i,j,k)][zy(0,j,k|(!i))] = 1;
}
a1[zy(i,j,k)][zy(1,j^1,k)] = 1;
ap[zy(i,j,k)][zy(1,j^1,k)] = 1;
}
for(int i = 0; i < 3; i++)
{
mul[0][i] = danw;
mat x;
if(!i)x = ap;
else x = mul[P][i - 1];
for(int j = 1; j <= P; j++) mul[j][i] = mul[j - 1][i] * x;
}
}
ll f[8];
void pus(mat x)
{
ll tmp[8];
memset(tmp, 0, sizeof tmp);
for(int i = 0; i < 8; i++)
for(int j = 0; j < 8; j++)
tmp[j] = (tmp[j] + f[i] * x[i][j]) % mod;
memcpy(f, tmp, sizeof f);
}
void appus(ll x)
{
if(x % P != 0)pus(mul[x % P][0]);
if((x / P) % P != 0)pus(mul[(x / P) % P][1]);
if(x / P / P != 0)pus(mul[x / P / P][2]);
}
ll read()
{
ll x = 0;
char c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
return x;
}
void slove()
{
n = read();
m = read();
memset(f, 0, sizeof f);
f[zy(1,1,0)] = 1;
ll ss = 1;
for(int i = 1; i <= m; i++)
{
ss = ss * 2 % mod;
a[i] = read();
v[i] = read();
appus(a[i] - a[i - 1] - 1);
if(v[i] == 0)pus(a0);
else pus(a1);
}
appus(n - a[m]);
int w = (n - 1) / 2 % 2;
ll ans = 0;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
ans = (ans + f[zy(i,w,j)]) % mod;
printf("%lld\n", ans * ss % mod);
}
int main()
{
init();
int t;
t = read();
while(t--)slove();
return 0;
}