程序员

CodeForces - 560E Gerald and Giant Chess(组合数学+dp)

作者:admin 2021-07-18 我要评论

题目链接 点击查看 题目大意给出一个 n ? m n*m n ? m 的矩阵其中有 k k k 个坏点每次只能向右走或向下走问从点 ( 1 , 1 ) (1,1) ( 1 , 1 ) 到点 ( n , m ) (n,m...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

题目链接:点击查看

题目大意:给出一个 n ? m n*m n?m 的矩阵,其中有 k k k 个坏点,每次只能向右走或向下走,问从点 ( 1 , 1 ) (1,1) (1,1) 到点 ( n , m ) (n,m) (n,m) 共有多少种不同的路线

题目分析:刷知乎看到的一道题,心血来潮就想写题了

数据范围 n , m n,m n,m 都是 1 e 5 1e5 1e5 级别的,而 k k k 却只有 2000 2000 2000,所以从坏点入手,考虑 d p dp dp 和组合数学

首先对于两个点 ( x 1 , y 1 ) (x1,y1) (x1,y1) ( x 2 , y 2 ) (x2,y2) (x2,y2) 来说,如果没有坏点的限制,那么这两个点之间的路线有 C ( x 2 ? x 1 ) + ( y 2 ? y 1 ) x 2 ? x 1 C_{(x2-x1)+(y2-y1)}^{x2-x1} C(x2?x1)+(y2?y1)x2?x1? 条,下面可以分两步进行思考,对于每个坏点 ( x , y ) (x,y) (x,y) 来说:

  1. 加上点 ( 1 , 1 ) (1,1) (1,1) 到点 ( x , y ) (x,y) (x,y) 之间方案数
  2. 对于每个满足 x x < = x xx<=x xx<=x y y < = y yy<=y yy<=y 的坏点 ( x x , y y ) (xx,yy) (xx,yy) 来说,点 ( 1 , 1 ) (1,1) (1,1) 经过点 ( x x , y y ) (xx,yy) (xx,yy) 然后到达点 ( x , y ) (x,y) (x,y) 的这些路线显然是不合法的,减去即可

综上所述,将所有坏点排序之后的转移方程就是(设 f ( x 1 , y 1 ) ( x 2 , y 2 ) f_{(x1,y1)}^{(x2,y2)} f(x1,y1)(x2,y2)? 为坏点 ( x 1 , y 1 ) (x1,y1) (x1,y1) 到坏点 ( x 2 , y 2 ) (x2,y2) (x2,y2) 的方案数, d p i dp_i dpi? 为点 ( 1 , 1 ) (1,1) (1,1) 到第 i i i 个坏点的方案数):
d p i = f ( 1 , 1 ) ( p i . x , p i . y ) ? [ p j . x < = p i . x ? & & ? p j . y < = p i . y ] ? d p j ? f ( p i . x , p i . y ) ( p j . x , p j . y ) dp_i=f_{(1,1)}^{(p_i.x,p_i.y)} \\ -[p_j.x<=p_i.x\ \&\&\ p_j.y<=p_i.y]*dp_j*f_{(p_i.x,p_i.y)}^{(p_j.x,p_j.y)} dpi?=f(1,1)(pi?.x,pi?.y)??[pj?.x<=pi?.x?&&?pj?.y<=pi?.y]?dpj??f(pi?.x,pi?.y)(pj?.x,pj?.y)?
将点 ( n , m ) (n,m) (n,m) 设为第 k + 1 k+1 k+1 个坏点,那么答案自然就是 d p k + 1 dp_{k+1} dpk+1?

代码:

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
const int mod=1e9+7;
struct Point {
	int x,y;
	void input() {
		read(x),read(y);
	}
	bool operator<(const Point& t)const {
		if(x!=t.x) {
			return x<t.x;
		}
		return y<t.y;
	}
}p[N];
LL dp[N],fac[N],inv[N];
LL q_pow(LL a,LL b) {
	LL ans=1;
	while(b) {
		if(b&1) {
			ans=ans*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
LL C(int n,int m) {
	if(n<m) {
		return 0;
	}
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void init() {
	fac[0]=1;
	for(int i=1;i<N;i++) {
		fac[i]=fac[i-1]*i%mod;
	}
	inv[N-1]=q_pow(fac[N-1],mod-2);
	for(int i=N-2;i>=0;i--) {
		inv[i]=inv[i+1]*(i+1)%mod;
	}
}
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	init();
	int n,m,k;
	read(n),read(m),read(k);
	for(int i=1;i<=k;i++) {
		p[i].input();
	}
	p[++k]={n,m};
	sort(p+1,p+1+k);
	for(int i=1;i<=k;i++) {
		dp[i]=C((p[i].x-1)+(p[i].y-1),(p[i].x-1));
		for(int j=1;j<i;j++) {
			if(p[i].x>=p[j].x&&p[i].y>=p[j].y) {
				dp[i]=(dp[i]-dp[j]*C((p[i].x-p[j].x)+(p[i].y-p[j].y),p[i].x-p[j].x)%mod+mod)%mod;
			}
		}
	}
	write(dp[k]);
    return 0;
}
;原文链接:https://blog.csdn.net/qq_45458915/article/details/115769132

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 数智洞察丨和死神赛跑,那些不得不“闯

    数智洞察丨和死神赛跑,那些不得不“闯

  • 酒店小程序开发瑞蚁解决方案

    酒店小程序开发瑞蚁解决方案

  • 自建Kubernetes集群如何使用阿里云CSI

    自建Kubernetes集群如何使用阿里云CSI

  • 【kafka运维】数据迁移、分区副本重分

    【kafka运维】数据迁移、分区副本重分

腾讯云代理商
海外云服务器