Description

小 A 和小 B 又想到了一个新的游戏.

这个游戏是在一个 \(1 \times n\) 的棋盘上进行的, 棋盘上有 \(k\) 个棋子, 一半是黑色, 一半是白色.

最左边是白色棋子, 最右边是黑色棋子, 相邻的棋子颜色不同.

小 A 可以移动白色棋子, 小 B 可以移动黑色的棋子, 他们每次操作可以移动 \(1\)\(d\) 个棋子.

每当移动某一个棋子时, 这个棋子不能跨越两边的棋子, 当然也不可以出界. 当谁不可以操作时, 谁就失败了.

小 A 和小 B 轮流操作, 现在小 A 先移动, 有多少种初始棋子的布局会使他胜利呢?

Input

共一行, 三个数,\(n, k, d\).

Output

输出小 A 胜利的方案总数. 答案对 \(10^9+7\) 取模.

Sample Input

10 4 2

Sample Output

182

Data Range

对于所有的数据, 满足:\(1 \leq d \leq k \leq n \leq 10000, 2 | k, k \leq 100\)

Explanation

题解传送门:http://hzwer.com/5760.html

题解传送门:http://blog.csdn.net/weixinding/article/details/7321139

\(k = 2\) 的情况, 显然是 A 胜利

A 第一步将其棋子紧靠 B, 则接下来 B 只能右移, 若 B 移动, A 下一步也能靠着它, 除非 A 一开始就无法移动

这样答案显然是 \(C_n^2 - (n - 1)\)

其实从 \(k = 2\) 的情况我们可以看出, B 的右移是没有意义的

因为 A 可以模仿 B, 同理 A 的左移是没有意义的, 那么就能转换为一个 nim 游戏

\(i\) 个白子, 匹配第 \(i\) 个黑子, 把他们中间的格子看成石子堆, 变成一个每次可以取 \(d\) 堆的 nim 游戏

结论: 必败态是把每堆石子转换为二进制后, 其中每一位上为 1 的石子堆数都能被 \((d + 1)\) 整除

\(f[i][j]\) 表示考虑二进制前 \(i\) 位, 放置了 \(j\) 个石头的方案数, 枚举每一位

\(q(d+1)\) 堆是 \(1\), 即放了 \(q(d+1) \cdot 2^i\) 个, 用排列组合计算这 \(q(d+1)\) 堆是 \(k\) 堆中的那些

\[f[i+1][j+k(d+1) \cdot 2^i] += f[i][j] \cdot C_{\frac{K}{2}}^{k(d+1)}\]

然后用总方案-必败局面数, 总方案显然是 \(C_n^k\)

2015-11-22

其实转成 nim 游戏是有误的

这个游戏往左移, 是可以加石子的, 虽然后手可以模仿, 但是要消耗下次可操作的堆数, 并非没有意义

反例: d=2

[] OX [] O [] XO [] XO [] X 0 1 1 1

前两个白棋往两边移动

O [] X [] [] OXO [] XO [] X 1 0 1 1

必败能转移成必败!

所以题目中要增加限制: 先手不能左移, 后手不能右移

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>

#define pow2(__x) (1<<(__x))
#define safe_add(__x,__y) __x=(((__x)+(__y))%modr)
using namespace std;
typedef long long lli;
const int maxn = 10010;
const lli modr = 1000000007ll;

lli n, K, d;
lli C_ar[maxn][210], dp[30][maxn];

lli C(int n, int m)
{
    m = min(m, n - m);
    return C_ar[n][m];
}

int main(int argc, char** argv)
{
    scanf("%lld%lld%lld", &n, &K, &d);
    K /= 2; // This looks better than an even number
    // Generating combinatory numbers using Yang Hui triangle
    for (int i = 0; i <= n; i++)
        C_ar[i][0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= min(2*K, (lli)i); j++)
            C_ar[i][j] = (C_ar[i-1][j] + C_ar[i-1][j-1]) % modr;
    // Working
    dp[0][0] = 1;
    for (int i = 0; i < 15; i++)
        for (int j = 0; j <= n - 2*K; j++)
            for (int k = 0; k*(d+1)<=K && j+k*(d+1)*pow2(i)<=n-2*K; k++)
                safe_add(dp[i+1][j+k*(d+1)*pow2(i)], dp[i][j]*C(K,k*(d+1)));
    lli tmp = 0;
    for (int i = 0; i <= n-2*K; i++)
        safe_add(tmp, dp[15][i]*C(n-i-K, K));
    lli sum = C(n, K*2);
    lli res = (sum - tmp + modr) % modr;
    printf("%lld\n", res);
    return 0;
}