AcWing 306. 杰拉尔德和巨型象棋 计数类DP

参考秦大佬的题解: https://www.acwing.com/solution/AcWing/content/1730/


//通过容斥原理
//那么F[i]表示为从左上角走到第i个黑色格子,而且途中不经过其他黑色格子的方案数
//终点作为第k+1个黑格子

//F[i]=(1,1)到(xi,xj)的总方案数-前(i-1)黑格方案数*黑格到(xi,yi)的方案数
//其中, (1,1)到(xi,xj)的总方案数为C(xi-1+yi-1,xi-1)

#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=200020;
const int mod=1e9+7;
int n,m,k;
int fact[N], infact[N];
pair<int,int>date[N];
int f[N];
typedef long long LL;
int qmi(int a,int k,int p)
{
    int res=1%p;
    while(k)
    {
        if(k&1)
			res=res*a%p;
        a=a*a%p;
        k >>= 1;
    }
    return res;
}
int C(int a,int b)
{
	return fact[a]*infact[b]%mod*infact[a-b]%mod;
}
signed main()
{
	cin>>n>>m>>k;
    for(int i=1;i<=k;i++)
    	cin>>date[i].first>>date[i].second;
    fact[0]=infact[0]=1;
    for(int i=1;i<N;i++)
    {
        fact[i]=(LL)fact[i-1]*i%mod;
        infact[i]=(LL)infact[i-1]*qmi(i,mod-2,mod)%mod;
    }
    sort(date+1,date+1+k);
    date[k+1]=make_pair(n,m);
    f[0]=1;

	for(int i=1;i<=k+1;i++)
	{
		int x=date[i].first,y=date[i].second;
		f[i]=C(x+y-2,x-1);
		for(int j=1;j<i;j++)
		{
			int a=date[j].first,b=date[j].second;
			if(a<=x && b<=y)
				f[i]=(f[i]-f[j]*(long long)C(x-a+y-b,x-a))%mod;
		}
	}
	cout<<(f[k+1]+mod)%mod<<endl;
	return 0;
} 

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12601042.html

时间: 2024-10-11 00:14:50

AcWing 306. 杰拉尔德和巨型象棋 计数类DP的相关文章

$Poj1737\ Connected\ Graph$ 计数类$DP$

AcWing Description 求$N$个节点的无向连通图有多少个,节点有标号,编号为$1~N$. $1<=N<=50$ Sol 在计数类$DP$中,通常要把一个问题划分成若干个子问题,以便于执行递推. 一个连通图不容易划分,而一个不连通的无向图则很容易划分成结点更少的两部分.所以我们把问题转化成用$N$个点的无向图总个数减去$N$个点的不连通无向图的个数. $N$个点的无向图总个数显然是$2^{N*(N-1)/2}$,还是简单说下叭,就是$N$个点连成完全图的边数显然是$N*(N-1)

CH5E26 扑克牌 (计数类DP)

\(CH~5E26~*~\)扑克牌: (计数类DP) \(solution:\) 唉,计数类DP总是这么有套路,就是想不到. 这道题我们首先可以发现牌的花色没有价值,只需要知道每种牌有 \((0,4]\) 张,牌的面值也不用管,只需要知道总共有 \((0,13]\) 种牌.然后我们就可以设出状态: \(f[i][j][p][q]\) 表示还剩 \(1\) 张有 \(i\) 种牌的,还剩 \(2\) 张牌的有 \(j\) 种,还剩 \(3\) 张牌的有 \(p\) 种,还剩 \(4\) 张牌的有

0x50 动态规划(0x5C 计数类DP)例题3:装饰围栏(题解)(计数类DP讲解,确定第k个排列)

计数类DP一般就是确定DP状态,DP出排名范围,然后不断逼近. 题意 题目链接 [题目描述] 有 N 块长方形的木板,长度分别为1,2,-,N,宽度都是1. 现在要用这 N 块木板组成一个宽度为 N 的围栏,满足在围栏中,每块木板两侧的木板要么都比它高,要么都比它低. 也就是说,围栏中的木板是高低交错的. 我们称"两侧比它低的木板"处于高位,"两侧比它高的木板"处于低位. 显然,有很多种构建围栏的方案. 每个方案可以写作一个长度为N的序列,序列中的各元素是木板的长度

codeforces 277.5 div2 F:组合计数类dp

题目大意: 求一个 n*n的 (0,1)矩阵,每行每列都只有两个1 的方案数 且该矩阵的前m行已知 分析: 这个题跟牡丹江区域赛的D题有些类似,都是有关矩阵的行列的覆盖问题 牡丹江D是求概率,这个题是方案数,也比较相似.. 这种题中,因为只要求方案数..我们只要关注几行几列有几个1,而不必要关注具体的位置 题解: 行列都需要处理,因此考虑记录列的状态,然后一行一行的转移 最暴力的方程: dp[i][j][k][t] 表示已经确定了 i 行 有 j列已经有两个1,有k列只有一个1,有t列一个1也没

hackerrank【Lego Blocks】:计数类dp

题目大意: 修一个层数为n,长度为m的墙,每一层可以由长度为1.2.3.4的砖块构成. 每一层都在同一个长度处出现缝隙是方案非法的,问合法的方案数有多少种 思路: 先求出总方案,再减去所有非法的方案数 总方案数容易求得,略 非法方案数就不太好求了,由于需要判重,我们可以按照 " 最左边的缝隙 " 所在的位置给非法方案数分类 这样就不会有重复了! 具体见代码: #include<stdio.h> #include<string.h> #include<ios

51 nod 1610 路径计数(Moblus+dp)

1610 路径计数 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 路径上所有边权的最大公约数定义为一条路径的值. 给定一个有向无环图.T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对1,000,000,007取模). Input 第一行两个整数n和m,分别表示有向无环图上的点数和边数.(1<=n<=100,1<=m<=50,000) 第2~m+1行每行三个数x,y,z,表示有一条从x到y权值为z的边.(1

计数类问题专题

主要是前两天被uoj的毛爷爷的题虐的不轻,心里很不爽啊,必须努力了,, 计数类问题分为:1.组合数学及数论计数 2.dp:状态压缩dp,插头轮廓线dp,树形dp,数位dp,普通dp 3.容斥原理 4.polya原理 5.图论计数 6.生成函数 7.其它(生成树计数等等) 本文主要研究前3个内容 考虑基本计数原理:加法原理,减法原理,乘法原理,除法原理 计数的基本原则:结果不重不漏 加法原理比较自然,中间过程有时减法原理 考虑到无向,有向图的各种量值(生成树之类)计数,状态压缩dp解决 论文:ht

【BZOJ-1833】count数字计数 数位DP

1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2494  Solved: 1101[Submit][Status][Discuss] Description 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. Input 输入文件中仅包含一行两个整数a.b,含义如上所述. Output 输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次.

bzoj 2111: [ZJOI2010]Perm 排列计数 (dp+卢卡斯定理)

bzoj 2111: [ZJOI2010]Perm 排列计数 1 ≤ N ≤ 10^6, P≤ 10^9 题意:求1~N的排列有多少种小根堆 1: #include<cstdio> 2: using namespace std; 3: const int N = 1e6+5; 4: typedef long long LL; 5: LL m, p, T, x, y, F[N]; 6: LL n, size[N<<1]; 7: LL f[N]; 8: LL inv(LL t, LL