首页 > 其他分享 >P2490 [SDOI2011]黑白棋

P2490 [SDOI2011]黑白棋

时间:2023-04-13 17:15:27浏览次数:42  
标签:黑白棋 return int res SDOI2011 P2490 dp define

题意:一个1*n的棋盘上有k个棋子,一半是黑一半是白,并且是白黑白黑白黑...白黑的形式,A每次最多可以将d个白棋子向右移动,B每次最多可以将d个黑棋子向左移动,不能不移动棋子,谁最后无法移动棋子谁就输了,A先手,问有多少种布局可以使得A获胜

Solution

Nim-K博弈+动态规划

可以把棋子之间的间隔看做是石子的堆数,那么就变成了Nim-K问题

如果所有数上每一位的1的个数%(d+1)==0,这种就是必败的,我们用总的减去必败的就是答案

令dp[i] [j]表示1-i位上异或和为0,用了j个石子的方案数

那么对于下一位而言,每次转移的时候都必须改变这一位上(d+1)个数才行,我们枚举(d+1)的个数x*(d+1)

在k/2堆石子里面选取x(d+1)个,于是有
$$
dp[i+1][j+x
(1<<i)(d+1)]+=dp[i][j]C(k/2,x(d+1))
$$
最后统计方案数的时候,需要考虑每一堆石子的位置,去掉需要空的间隔总共i个空格以及k/2个终点的位置,在其中选出k/2个起点,一共有Σdp[最高位] [i]
C(n-i-k/2,k/2)

答案就是ans-Σdp[最高位] [i]*C(n-i-k/2,k/2)

// Problem: P2490 [SDOI2011]黑白棋
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2490
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long
//#define INF 0x3f3f3f3f3f3f3f3f
#define INF 0x3f3f3f3f
#define FOR(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int lowbit(int x) { return -x & x; } 
//const int mod = 998244353;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
const int M = 6e5 + 5;
int ksm(int x, int y, int mod1 = mod) {  
    int res = 1;
    x %= mod1;
    while (y > 0) {
        if (y & 1)
        {
            res = res * x % mod1;
        }
        y >>= 1;
        x = (x * x) % mod1;
    }
    return res;
}
int gcd(int a, int b)    
{
    return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b)    
{
    return a * b / gcd(a, b);
}
typedef pair<int, int> pii;


int fac[N];
int inv[N];
int C(int n,int m)
{
	if(n<m||m<0)return 0;
	else return ((fac[n]*inv[n-m])%mod*inv[m])%mod;
}
int dp[20][10005];


void solve()
{
	int n,k,d;cin>>n>>k>>d;
	fac[0]=1;
	for(int i=1;i<=100000;i++)
	{
		fac[i]=(fac[i-1]*i)%mod;
	}
	inv[100000]=ksm(fac[100000],mod-2);
	for(int i=99999;i>=0;i--)
	{
		inv[i]=(inv[i+1]*(i+1))%mod;
	}
	int sum=C(n,k);
	int res=0;
	dp[0][0]=1;
	//cout<<sum<<"\n";
	
	
	for(int i=0;i<=15;i++)
	{
		for(int j=0;j<=n-k;j++)
		{
			
			int p=1<<(i);
			for(int kk=0;j+p*kk*(d+1)<=n-k&&kk*(d+1)<=k/2;kk++)
			{
				dp[i+1][j+p*kk*(d+1)]=(dp[i+1][j+p*kk*(d+1)] + dp[i][j]*C(k/2,kk*(d+1))%mod)%mod;
			}
		}
	}
	
	for(int i=0;i<=n-k;i++)
	{
		sum=((sum-(dp[15][i]*C(n-i-k/2,k/2))%mod)%mod+mod)%mod;
	}
	cout<<sum<<"\n";
}
signed main(void) 
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
    int t = 1;
    //cin>>t;
    while (t--)
    {
        solve();
    }
    return 0;
}


标签:黑白棋,return,int,res,SDOI2011,P2490,dp,define
From: https://www.cnblogs.com/HikariFears/p/17315465.html

相关文章

  • 「分治」黑白棋子的移动
    本题为3月23日23上半学期集训每日一题中A题的题解题面题目描述有2n个棋子(n≥4)排成一行,开始位置为白子全部在左边,黑子全部在右边,如下图为n=5的情形:○○○○○●●●●......
  • P2495 [SDOI2011] 消耗战
     f[x]=SUM{min(f[y],z)}  (y是不重要的点)  建立虚树,然后dp #include<bits/stdc++.h>usingnamespacestd;constintN=3e6,M=N,inf=1e9;#d......
  • P2489 [SDOI2011]迷宫探险 题解
    题意简述:一个\(n\timesm\)的带墙体单入口多出口迷宫中有\(k\)个陷阱,陷阱分为有害或无害,有害会使人掉血,给出所有垃圾的有害与无害的所有排列组成的概率,给定人的血量,求......
  • 洛谷P1259 黑白棋子的移动 题解
    本蒟蒻这题用的打表做法,其实也可以理解为是一种递推。先来观察一下样例:当n为7时,输出共有14行,易得输出行数为2n。ooooooo*******--oooooo--******o*oooooo******--o......
  • 课程设计 --- 黑白棋中的 AI
    到了考试周了佯,可是偏偏这个时候迎来了很多很多的课程设计,幸好教授把C语言的课程设计提前发出了,不然都在最后几周,加上数据结构的课程设计就没有时间做这个啦~刚开始打算做成......
  • 【SDOI2011】【BZOJ2242】计算器
    Description你被要求设计一个计算器完成以下三项任务:1、给定y、z、p,计算y^zmodp的值;2、给定y、z、p,计算满足xy≡z(modp)的最小非负整数;3、给定y、z......
  • 黑白棋盘工具
     按C键复制图片到剪贴板。按Z键悔棋。默认是左图圆棋子。很容易改成方形棋子。https://files.cnblogs.com/files/blogs/714801/BrdTool.zip19KB含源码和.exe有效的代......
  • P2484 [SDOI2011]打地鼠 题解
    P2484[SDOI2011]打地鼠题解目录P2484[SDOI2011]打地鼠题解题目分析思路代码题目P2484[SDOI2011]打地鼠题解分析锤子每次只能将每个洞里打掉一只地鼠,所以对于每......
  • 【XSY1976】【BZOJ2286】【SDOI2011】消耗战(虚树,dp)
    这题的dp思想还是比较容易想的,关键是如何保证时间复杂度,这时就用到了虚树的技巧。1.虚树是什么?(虚树的性质)不妨设现在询问给出了\(k\)个点,我们命名这些节点为关键节点。......
  • P2486 [SDOI2011]染色
    #include<iostream>#include<vector>usingnamespacestd;#defineintlonglongconstintN=1e5+1;intn,m;vector<int>to[N];intdep[N],fa......