团不过
- problem
- solution
- code
problem
由比滨结衣和雪之下雪乃在玩 NimNimNim 游戏。
共有 nnn 堆石子,双方轮流操作,每次可以从一堆非空石子堆中取走任意个石
子,取走最后一个石子的人胜利。
她们决定让由比滨结衣先手,但忘记了每堆初始时含有石子的数目,只知道
每堆至少有 111 个石子,但数目小于 2n2^n2n ,且每堆石子的数目互不相同。
一共有多少种可能的情况使得由比滨结衣能够取胜呢?
两种情况不同当且仅当存在一堆石子在两种情况中含有的石子数目不同。
由于答案可能很大,你只需要输出答案对 109+710^9 + 7109+7 取模的结果。
友情提示:在 NimNimNim 游戏中,先手必胜等价于各堆石子数目异或之和不为 000 。
n≤1e7n\le 1e7n≤1e7。
solution
正睿原题我是nm没想到,还有人写过题解,草!我已经跟他们隔了一层可悲的厚障壁了!qwq
考虑在限定每堆石子个数互不相同的情况下,用总方案数减去先手必败的方案数。
设 pi:ip_i:ipi:i 堆石子的方案数,即 ∑k=1i(2n−1−k+1)\sum_{k=1}^i(2^n-1-k+1)∑k=1i(2n−1−k+1)。
设 fi:if_i:ifi:i 堆石子的游戏下,先手必败的方案数。
考虑 fif_ifi 的转移。
- 如果前 i−1i-1i−1 堆石子异或和为 000 ,则第 iii 堆石子只能是 000,但这不合法,所以要减掉 fi−1f_{i-1}fi−1。
- 如果其中有 i−2i-2i−2 堆石子异或和为 000,则第 iii 堆石子必须和剩下的一堆石子相同,也不合法,所以要减去 fi−2⋅(i−11)⋅(2n−1−(i−2))f_{i-2}·\binom{i-1}{1}·(2^n-1-(i-2))fi−2⋅(1i−1)⋅(2n−1−(i−2))【(i−11)\binom{i-1}{1}(1i−1)枚举除了哪堆石子外其余石子异或和为 000,(2n−1−(i−2))(2^n-1-(i-2))(2n−1−(i−2))减去 i−2i-2i−2 堆互不相同的石子数,剩下的可选数目即为第 iii 堆石子和剩下一堆石子的数量。】
即 fi=pi−1−fi−1−fi−2⋅(i−1)⋅(2n−i+1)f_i=p_{i-1}-f_{i-1}-f_{i-2}·(i-1)·(2^n-i+1)fi=pi−1−fi−1−fi−2⋅(i−1)⋅(2n−i+1)。
边界情况 f1=f2=0f_1=f_2=0f1=f2=0。
时间复杂度 O(n)O(n)O(n)。
code
#include <cstdio>
#define int long long
#define maxn 10000005
#define mod 1000000007
int n, x, cnt;
int Pow[maxn], f[maxn];int qkpow( int x, int y ) {int ans = 1;while ( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}signed main() {freopen( "yui.in", "r", stdin );freopen( "yui.out", "w", stdout );scanf( "%lld", &n );Pow[0] = 1; cnt = x = qkpow( 2, n ) - 1;for( int i = 1;i <= n;i ++ ) Pow[i] = Pow[i - 1] * cnt % mod, cnt --;f[1] = f[2] = 0;for( int i = 3;i <= n;i ++ ) f[i] = ( Pow[i - 1] - f[i - 1] - ( i - 1 ) * ( x - i + 2 ) % mod * f[i - 2] % mod ) % mod;printf( "%lld\n", ( ( Pow[n] - f[n] ) % mod + mod ) % mod );return 0;
}