列表

详情


NC20350. [SDOI2011]黑白棋

描述

小A和小B又想到了一个新的游戏。 
这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色。 
最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同。 小A可以移动白色棋子,小B可以移动黑色的棋子,他们每次操作可以移动1到d个棋子。 
每当移动某一个棋子时,这个棋子不能跨越两边的棋子,当然也不可以出界。当谁不可以操作时,谁就失败了。 
小A和小B轮流操作,现在小A先移动,有多少种初始棋子的布局会使他胜利呢?

输入描述

共一行,三个数,n,k,d。

输出描述

输出小A胜利的方案总数。
答案对1000000007取模。

示例1

输入:

10 4 2

输出:

182

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 16ms, 内存消耗: 9976K, 提交时间: 2019-03-30 20:48:22

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10005, maxm = 105, inf = 1000000000, p = 1000000007;
ll c[maxn][maxm], f[20][maxn];
int main()
{
    ll n, k, D;
    cin >> n >> k >> D;
    for(int i = 0; i <= n; i++)
    {
        c[i][0] = 1;
        for(int j = 1; j <= i && j <= k; j++)
        {
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % p;
        }
    }
    f[0][0] = 1;
    for(ll i = 0; i <= 16; i++)
    {
        for(ll j = 0; j <= n - k; j++)
        {
            for(ll x = 0; x * (D + 1) <= k / 2 && x * (D + 1) * (1ll << i) + j <= n - k; x++)
            {
                f[i + 1][j + x * (D + 1) * (1ll << i)] =
                (f[i + 1][j + x * (D + 1) * (1ll << i)] + f[i][j] * c[k/2][x * (D + 1)]) % p;
            }
        }
    }
     ll ans = c[n][k];
     for(int i = 0; i <= n - k; i++)
     {
         ans = (ans - f[16][i] * c[n - k - i + k / 2][k / 2] % p) % p;
     }
     cout << (ans + p) % p << endl;
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 14ms, 内存消耗: 10220K, 提交时间: 2019-03-09 21:28:49

#include<stdio.h>
#include<string.h>
#define mod 1000000007
#define LL long long
LL C[10005][105], dp[18][10005], er[18] = {1};
int main(void)
{
	LL i, j, n, k, d, x, ans;
	for(i=0;i<=10000;i++)
		C[i][0] = 1;
	for(i=1;i<=15;i++)
		er[i] = er[i-1]*2;
	for(i=1;i<=10000;i++)
	{
		for(j=1;j<=100;j++)
			C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod;
	}
	while(scanf("%lld%lld%lld", &n, &k, &d)!=EOF)
	{
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1;
		for(i=0;i<=15;i++)
		{
			for(j=0;j<=n-k;j++)
			{
				dp[i+1][j] = (dp[i+1][j]+dp[i][j])%mod;
				for(x=1;x*(d+1)*er[i]+j<=n-k&&x*(d+1)<=k/2;x++)				//总石子数不能超过n-m,并且第i位二进制为1的石子堆数不能超过总堆数
					dp[i+1][j+x*(d+1)*er[i]] = (dp[i+1][j+x*(d+1)*er[i]]+dp[i][j]*C[k/2][x*(d+1)]%mod)%mod;
			}
		}
		ans = 0;
		for(i=0;i<=n-k;i++)
			ans = (ans+dp[15][i]*C[n-i-k/2][k/2])%mod;
		printf("%lld\n", ((C[n][k]-ans)%mod+mod)%mod);
	}
	return 0;
}

上一题