跪着%yyy半年前秒掉的题
题目大意:经典的取石子游戏,但规定取走的石子数必须与当前这堆的石子总数互质。现在求堆数为 107 ,每堆石子的数目为[1, 107 )中,有多少种先手必败的可能。
嗯……先打表……
发现如下规律
sg[n]=⎧⎩⎨⎪⎪⎪⎪10ksg[ms[n]]n==1n==2n为第k个素数otherwise
现在就是要求xor等于0的方案数
倍增,滋磁
设f[i,j]表示前 2i 个数异或为j的方案数
fwt转移
【答案】994345168
#include <iostream>
#include <cstdio>
#define LL long long
#define M 1000000007
using namespace std;
const int N = 1048576,n = 10000000;
int tot,inv2;
int sg[n + 10],prime[n + 10],v[n + 10];
LL f[24][N],ans[N];
LL ksm(LL a,int b)
{
LL ret = 1;
for (;b;b >>= 1,a = a * a % M)
if (b & 1) ret = ret * a % M;
return ret;
}
void get_prime()
{
sg[1] = 1;
for (int i = 2;i < n;i ++)
{
if (!v[i])
{
prime[tot ++] = i;
if (i ^ 2) sg[i] = tot;
}
for (int j = 0;j < tot && i * prime[j] < n;j ++)
{
v[i * prime[j]] = 1;
sg[i * prime[j]] = sg[prime[j]];
if (i % prime[j] == 0) break;
}
}
}
void DWT(LL *a,int l,int r)
{
if (l == r) return;
int m = l+r >> 1;
DWT(a,l,m),DWT(a,m+1,r);
for (int i = 0;i <= m - l;i ++)
{
LL x = (a[i + l] + a[m + 1 + i]) % M,y = (a[i + l] - a[m + 1 + i]) % M;
a[i + l] = x,a[m + 1 + i] = y;
}
}
void IDWT(LL *a,int l,int r)
{
if (l == r) return;
int m = l+r >> 1;
for (int i = 0;i <= m - l;i ++)
{
LL x = (a[i + l] + a[m + 1 + i]) % M * inv2 % M;
LL y = (a[i + l] - a[m + 1 + i]) % M * inv2 % M;
a[i + l] = x,a[m + 1 + i] = y;
}
IDWT(a,l,m),IDWT(a,m+1,r);
}
int main()
{
get_prime(),inv2 = ksm(2,M-2);
for (int i = 1;i < n;i ++) f[0][sg[i]] ++;
DWT(f[0],0,N-1);
for (int i = 1;i < 24;i ++)
for (int j = 0;j < N;j ++) f[i][j] = f[i - 1][j] * f[i - 1][j] % M;
ans[0] = 1,DWT(ans,0,N-1);
for (int i = 0;i < 24;i ++) if (n & (1 << i))
for (int j = 0;j < N;j ++) ans[j] = ans[j] * f[i][j] % M;
IDWT(ans,0,N-1);
cout << (ans[0] + M) % M << endl;
return 0;
}