首页 > 其他分享 >「SDOI2011」 黑白棋

「SDOI2011」 黑白棋

时间:2023-09-27 19:57:27浏览次数:36  
标签:黑白棋 matrix int dfrac times SDOI2011 ans mod

绷不住了,洛谷上的 dp 没一个表述清楚了,一怒之下写一篇题解。注意本题解只讲 dp 部分。

首先转化不合法的充要条件就是:设相邻两个棋子中间间隔数量为 \(b\),那么对于任意非负整数 \(i\) 都有 \((d+1)|\sum (b\& 2^i)\)。其中 \(\&\) 是按位与运算。所以我们要计数一个有序的并且包含 \(\dfrac{k}{2}\) 个元素的 \(b\) 数组。

那么我们考虑 \(f_{i,j}\) 表示这 \(\dfrac{k}{2}\) 个数每个都填了二进制上前 \(i\) 位并且这 \(i\) 位满足是 \(d+1\) 倍数的条件,并且选出数字总和为 \(j\) 的方案数。那么这时我们就可以枚举第 \(i+1\) 位的填数字情况,很显然是要填 \(p(d+1)\) 个 \(1\),其中 \(p\in\mathbf{N}\)。我们就枚举 \(p\),那么总和增量就是 \(2^i\times p(d+1)\);我们可以考虑哪些位置选了数,那么产生的贡献就是 \(f_{i,j}\times\left(\begin{matrix}\dfrac{k}{2}\\p(d+1)\end{matrix}\right)\) 这么多,加到 \(f_{i,j+2^i\times p(d+1)}\) 上。

最后我们要通过 \(b\) 数组还原棋子的排布情况,那么我们枚举 \(j\),由于有 \(j+\dfrac{k}{2}\) 个位置是不能选的(间隔和终点),那么剩余的位置数量是 \(n-j-\dfrac{k}{2}\),\(j\) 对方案的贡献就是 \(f_{L,j}\times\left(\begin{matrix}n-j-\dfrac{k}{2}\\\dfrac{k}{2}\end{matrix}\right)\) 这么多。其中 \(L\) 是最高位。最后用 \(\left(\begin{matrix}n\\k\end{matrix}\right)\) 减去不合法答案的数量即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=10005,L=25,K=105,mod=1000000007;
int n,k,d,f[L][N],C[N][K];
inline void add(int&x,int y) {
    x=(x+y)%mod;
    return;
}
int main() {
    scanf("%d %d %d",&n,&k,&d);
    int lim=__lg(n);
    C[0][0]=1;
    for (int i=1;i<=n;i++) {
        C[i][0]=1;
        for (int j=1;j<=k;j++) {
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }
    f[0][0]=1;
    for (int i=0;i<=lim;i++) {
        for (int j=0;j<=n;j++) {
            for (int x=0;j+(x<<i)*(d+1)<=n&&x*(d+1)<=k/2;x++) {
                add(f[i+1][j+(x<<i)*(d+1)],1ll*f[i][j]*C[k/2][x*(d+1)]%mod);
            }
        }
    }
    int ans=0;
    for (int i=0;i<=n;i++) {
        if (n-i-k/2>=0) add(ans,1ll*f[lim+1][i]*C[n-i-k/2][k/2]%mod);
    }
    ans=(C[n][k]-ans+mod)%mod;
    printf("%d",ans);
    return 0;
}

标签:黑白棋,matrix,int,dfrac,times,SDOI2011,ans,mod
From: https://www.cnblogs.com/tulipenoire/p/17733781.html

相关文章

  • P2486 [SDOI2011] 染色 题解
    P2486[SDOI2011]染色神仙树剖题。题意给你一棵树,每个点都有颜色,支持下面两种操作:路径染色。路径颜色段数量查询。树剖部分我们看到树上问题,不好处理,所以想办法给他树剖搞一搞,给他转化成序列的操作。我们树剖就是正常的树剖,然后我们考虑如何维护这个颜色序列。我......
  • 「SDOI2011」计算器tj
    你被要求设计一个计算器完成以下三项任务:1.给定y、z、P,计算yzmodP的值2.给定y、z、P,计算满足xy≡z(modP)的最小非负整数x;3.给定y、z、P,计算满足yx≡z(modP)的最小非负整数x。输入第一行包含两个正整数T,K分别表示数据组数和询问类型-对于一个测试点内的所有数据,询问类......
  • P2484 [SDOI2011] 打地鼠
    题目描述2020.4.29数据更新。打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中。玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高。游戏中的锤子每次只能打一只地鼠,如果多只地鼠同时探出头,玩家只能通过多次挥舞......
  • BZOJ 2243: [SDOI2011]染色 树链剖分+线段树
    2243:[SDOI2011]染色TimeLimit: 20Sec  MemoryLimit: 512MBSubmit: 7623  Solved: 2855[Submit][Status][Discuss]Description给定一棵有n个节点的无根树和m个操作,操作有2类:1、将节点a到节点b路径上所有点都染成颜色c;2、询问节点a到节点b路径上的颜色段数量(连续......
  • NC20573 [SDOI2011]染色
    题目链接题目题目描述给定一棵有n个节点的无根树和m个操作,操作有2类:1、将节点a到节点b路径上所有点都染成颜色c;2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。请你写一个程序依次完成这m......
  • P2495 [SDOI2011] 消耗战 线段树合并做法
    看到题解里面有一个线段树合并做法!感觉很厉害,但是题解和代码都不是很详细所以补充一下不妨假设\(dp_u\)表示\(u\)及其子树内把所有关键点都切断的最小代价,那么不难有\[\begin{equation}dp_u=\begin{cases}+\infty&u是关键点\\\sum_{v\in\operatorname{son}(u)}\m......
  • BZOJ 2243 [SDOI2011] 染色 (树链剖分)
    题目地址:BZOJ2243普通的树链剖分,用线段树维护区间段数与最左边和最右边的颜色。然后当合并区间的时候判断一下左儿子的右端与右儿子的左端是否相同,若相同,则将和减去1.同样,在迭代求值的过程中,也要记录下上条链的最顶端的颜色。代码如下:#include<iostream>#include<strin......
  • P2490 [SDOI2011]黑白棋
    题意:一个1*n的棋盘上有k个棋子,一半是黑一半是白,并且是白黑白黑白黑...白黑的形式,A每次最多可以将d个白棋子向右移动,B每次最多可以将d个黑棋子向左移动,不能不移动棋子,谁最后无法移动棋子谁就输了,A先手,问有多少种布局可以使得A获胜SolutionNim-K博弈+动态规划可以把棋子之间的间......
  • 「分治」黑白棋子的移动
    本题为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......