首页 > 其他分享 >P5363 [SDOI2019]移动金币

P5363 [SDOI2019]移动金币

时间:2022-11-25 19:47:16浏览次数:43  
标签:金币 int LL P5363 SDOI2019 inv

P5363 [SDOI2019]移动金币

转化一下题意,移动一个金币相当于把这个金币前面的格子移到了后面,这是经典的阶梯\(\text{Nim}\),因为题目是把格子向后移,所以我们只要保证一共\(m + 1\)个数,\(\lfloor \frac{m + 1}{2}\rfloor\)个数的异或和不为\(0\),所有的数和为\(n - m\),这样我们可以\(O(mn^3)\)\(DP\),但我们发现有太多的无用的状态了,考虑求出异或和为零的方案数,再用全部方案数减去其。
那么我们可以考虑按位来\(DP\),每一位上\(1\)的个数为偶数即可,设\(f_{i,j}\)表示考虑到了第\(i\)位,当前所有的数和为\(j\),那么转移为

\[f_{i,j} = \sum_{2|k}f_{i,j - 2^i*k} * \dbinom{\lfloor \frac{m + 1}{2}\rfloor}{k} \]

答案再乘上其他数随便选的方案即可。

Code
#include<cstdio>
#define LL long long
using namespace std;
const int N = 150005, P = 1e9 + 9;
int n, m; LL f[30][N], fac[N], inv[N];

LL getc(int x, int y){return fac[x] * inv[y] % P * inv[x - y] % P;}
int main() {
	scanf("%d%d",&n,&m), fac[0] = inv[0] = inv[1] = 1;
	for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * (LL)i % P;
	for (int i = 2; i <= n; i++) inv[i] = (P - P / i) * inv[P % i] % P;
	for (int i = 2; i <= n; i++) inv[i] = inv[i] * inv[i - 1] % P;
	int bit = 0, z = n - m; while (z) z >>= 1, bit++;
	f[0][0] = 1;
	for (int i = 1; i <= bit; i++)
		for (int j = 0; j <= n - m; j++)
			for (int k = 0; k <= (m + 1 >> 1) && (1 << i - 1) * k <= j; k += 2)
				(f[i][j] += f[i - 1][j - (1 << i - 1) * k] * getc(m + 1 >> 1, k) % P) %= P;
	LL ans = 0; int a = (m + 1 >> 1) - 1, b = m >> 1;
	for (int j = 0; j <= n - m; j++)
		(ans += (getc(j + a, a) - f[bit][j] + P) * getc(n - m - j + b, b) % P) %= P;
	printf("%lld\n", ans);
}

标签:金币,int,LL,P5363,SDOI2019,inv
From: https://www.cnblogs.com/nibabadeboke/p/16926178.html

相关文章

  • 基于QT和C++实现的翻金币游戏
    基于QT和C++的翻金币游戏声明:QT翻金币项目可以说是每个新学QT的同学都会去写的一个项目,网上的源码也很多,我也是最近刚开始学QT,所以也参考了很多前辈的代码自己重新敲了一......
  • noi 1.5 45 金币
    描述国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天)里,每天收到两枚金币;之后三天(第四、五、六天)里,每天收到三枚金币;之后四天(第七、八......
  • 1.5.45:金币
    题目链接题意:第一天为1*该段时间天数之后两天2*该段时间天数在之后三天3*该段时间天数每段时间获得的金币就是该段时间天数*该段时间天数最后算出n天一共得了......
  • MVC实现金币添加
     其实代码部分没有什么变化,就是原来所有代码放到一起,mvc的话把他们分类了先建几个文件、脚本  Model层代码  Controller层代码 View层代码  此时co......
  • 背包系统-金币添加
    1.实现金币添加  实现:点击加号,实现金币添加  这里的金币值是一个文本,加号是一个按钮实现步骤:①定义文本  ②获取加号按钮,再给他添加一个事件(事件绑定(基础......
  • [2015年NOIP普及组] 金币
    #include<iostream>intmain(){intstep=1;intcoin=1;intnow;std::cin>>now;intcount=0;intwalk=0;for(intday=1;day<=now;da......
  • [2015年NOIP普及组] 金币
    [2015年NOIP普及组]金币思路:第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收......
  • [2015年NOIP普及组] 金币
    模拟出每天骑士获得的金币,加起来#include<bits/stdc++.h>usingnamespacestd;intmain(){ intn,i,j=0,s=0,bj=1; cin>>n; for(i=1;i<=n;i++){ j++; s=s+bj; if(j==bj......