【GDOI2020模拟03.28】数二数(two) (计数动态规划):

?

先考虑如何判断一个询问集是否合法。

考虑询问一次\([l,r]\),能把\([1,l-1]∪[r+1,n]\)和\([l,r]\)区分开来。

现在定义一个块为一个没有被区分开极大的点集合。

当所有块的大小都是1的时候,这个方案就是合法。

?

性质:

1.一个块是由若干连续段组成,比如下面这样:

1112233111411

颜色为1的块由三段连续段。

?

2.块与块之间不会出现交叉的情况:

比如下面这样:

11122211122211

也就说两个块的关系,只有完全包含和互不相交两种。

?

设\(f[i]\)表示长度为\(i\),每个块大小都是1的方案数。

考虑用总的减去不合法的。

不合法的方案数:先枚举一种不合法的块的划分状态,再考虑求变成这样有多少种方案。

对于一个不合法的块的划分状态,我们可以只取其最外层的块的最左点和最右点来统计它。

最外层的块:不被任何其他块包含的块。

比如\(112131145657\),保留为:\(1?????145?57\)

对于\(??…?\)中间的边,可以随便取。

对于保留下来的块\(1、4、5、7\),它们之间要区分,方案数就是\(f[最外层块数]\)

?

转移:

考虑枚举大小\(>1\)的最外层块的个数,再枚举要插进大小\(>1\)的最外层块中间的\(?\)的个数y,则大小\(=1\)的最外层块数\(z=i-2x-y\)

预处理个\(g[i][j]\)表示把\(j\)个数插进\(i\)个块的系数积的和,\(g[i][j]=\sum_{k=1}^jg[i-1][j-k]*2^{k(k+1)/2}\)

那么\(f[i]=2^{i(i+1)/2}-\sum_x\sum_{y,z=i-2x-y} g[x][y]*f[x+z]*{(x+z)!\over x!z!}\)

其中\({(x+z)!\over x!z!}\)是最外层块的排列方案数。

?

Code:


#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

int n, mo;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

const int N = 305;

ll a2[N * N + N];
ll f[N], h[N][N];
ll fac[N], nf[N];

int main() {
	freopen("two.in", "r", stdin);
	freopen("two.out", "w", stdout);
	scanf("%d %d", &n, &mo);
	a2[0] = 1; fo(i, 1, (n + 1) * n) a2[i] = a2[i - 1] * 2 % mo;
	f[1] = 1;
	fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
	fd(i, n, 0) nf[i] = ksm(fac[i], mo - 2);
	h[0][0] = 1;
	fo(i, 0, n - 1)	{
		fo(j, 0, n) fo(k, 0, n - j)
			h[i + 1][j + k] = (h[i + 1][j + k] + h[i][j] * a2[k * (k + 1) / 2]) % mo;
	}
	f[1] = 2;
	fo(i, 2, n) {
		f[i] = a2[i * (i + 1) / 2];
		fo(x, 1, i / 2) fo(y, 0, i - 2 * x) {
			int z = i - 2 * x - y;
			ll v = h[x][y] * f[i - y - x] % mo;
			v = v * fac[z + x] % mo * nf[z] % mo * nf[x] % mo;
			f[i] = (f[i] - v) % mo;
		}
	}
	pp("%lld\n", (f[n] % mo + mo) % mo);
}

原文地址:https://www.cnblogs.com/coldchair/p/12589976.html

时间: 2024-10-08 07:59:50

【GDOI2020模拟03.28】数二数(two) (计数动态规划):的相关文章

6516. 【GDOI2020模拟03.28】数二数(two)

题目 有一个\([1,n]\)的整数,可以询问\([L,R]\),表示整个整数是否在这个区间里. 计算有多少个询问集合,使得这些询问过后,无论整数是\([1,n]\)中哪一个都能被唯一确定. \(n\leq 300\) 思考历程 简化一下题目大意:可以通过询问,将数字分成若干组. 一开始\([1,n]\)为一组. 某个询问\([L,R]\)之后,将这个东西与当前分成的若干组分别取交,从而进一步分组. 到最后如果每一组如果仅仅包含一个数字,那么就是一种合法的方案. 我只会强行状压DP--然而并没有

2019考研数学题源探析经典1000题习题+解析分册(数一+数二+数三)

资源链接:https://pan.baidu.com/s/1gnDlPrVEQG6bd003Un-5Kg2019考研数学题源探析经典1000题习题+解析分册(数一+数二+数三)考研数学刷题必备!如下: 原文地址:http://blog.51cto.com/14084127/2320170

6439. 【GDOI2020模拟01.17】小 ω 数排列

题目描述 Description Input Output Sample Input Sample Input1 4 10 3 6 2 9 Sample Input2 8 35 3 7 1 5 10 2 11 6 Sample Output Sample Output1 6 [样例 1 解释] 共有 6 个排列符合条件,它们是 (1, 3, 2, 4),(2, 4, 1, 3),(3, 1, 2, 4),(3, 1, 4, 2),(4, 2, 1, 3),(4, 2, 3, 1). Sample

【GDOI2020模拟4.11】赢家(winner) (计数dp+容斥)

题目描述: PinkRabbit 是一位人赢. 福州市可以抽象成一个n个点m条边的,不包含重边与自环的无向图,PinkRabbit 住在1号 点,而他的妹子住在2号点. 某一天,PinkKitten 施放了一个大魔法,让这个无向图上所有的边都变成了单向边.现在 PinkRabbit 关心的是他是否能够和他的妹子见面. 具体地,PinkRabbit 能和他的妹子见面,当且仅当存在一个点 u,满足新图上从1号点出发能够 到达u,从2号点出发也能到达 . 现在你需要计算出,在把所有 m条边进行定向的所

【Nowcoder 上海五校赛】二数

题目描述: 我们把十进制下每一位都是偶数的数字叫做"二数". 小埃表示自己很聪明,最近他不仅能够从小数到大:2,3,4,5....,也学会了从大数到小:100,99,98...,他想知道从一个数开始数最少的数就得到一个二数.但是聪明的小森已经偷偷在心里算好了小埃会数到哪个二数,请你求出他要数到哪个数吧. 换句话说,给定一个十进制下最多105位的数字,请你求出和这个数字的差的绝对值最小的二数,若答案不唯一,输出最小的那个. 也就是说,给定数字n,求出m,使得abs(n-m)最小且m[i]

[转帖]从麒麟阁到凌烟阁,数一数各朝代开国功臣名将

从麒麟阁到凌烟阁,数一数各朝代开国功臣名将 http://www.sohu.com/a/232660923_717027 2018-05-23 21:33 中国5000年历史,朝代更替,很多人跟随君主打天下,图的是功成名就,拜将封侯.功臣们获得至高无上的荣誉,享受人间繁华,这是用热血换来的回报,也是应该得到的尊荣. 西汉初年,汉高祖刘邦将萧何.曹参.宣张敖.周勃.樊哙等18人封侯,首次封赏开国功臣. 公元前51年,西汉宣帝刘询因匈奴归降大汉,回忆往昔辅佐有功之臣,令人画名功臣图像于麒麟阁以示纪念

12月28日 二维数组的应用:第一个小游戏(推箱子)

小游戏:******推箱子******** static void Main(string[] args) { int i, j; int[,] a = new int[10, 10]                  //二维数组的定义           类型[,] 数组名 = new  类型 [行数, 列数] {赋值}:   或单个赋值 a[i,j]=1; { {1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,2,0,0,8,0,0,0,

fzu Problem 2198 快来快来数一数 (快速幂+优化)

题目链接: Problem  2198  快来快来数一数 题目描述: 给出n个六边形排成一排,a[i]代表i个六边形能组成的生成树个数,设定s[i]等于a[1]+a[2]+a[3]+....+a[i-1]+a[i],问s[n]为多少? 解题思路: n取值范围[1, 1018],打表内存不够,然后就要考虑快速幂咯!纳尼!!!!快速幂写出来竟然超时,敢信?果然还是见题太少了.(GG) 对于a[n] = 6*a[n-1] - a[n-2],可以很明显看出. 然后求和的时候就要化简一番了,但是并不是很难

一群猴子排成一圈,按1,2,...,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈

一 群猴子排成一圈,按1,2,…,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停的 进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王.要求编程模拟此过程,输入m.n, 输出最后那个大王的编号 <?php //$n猴子个数 $m第几个位置 function fn( $n, $m){ //将猴子数量放到数组内 for($i = 1; $i < $n+1; $i++){ $arr[] = $i; } $i = 0; var_d