codeforces #313 div1 C

同BZOJ 3782 上学路线

QAQ 还比那个简单一点

把坐标(1,1)-(n,m)平移成(0,0)-(n-1,m-1)

设dp[i]表示从(1,1)出发第一次经过障碍且到达第i个障碍的方案数

首先到达第i个障碍的方案数为C(x+y,x)

之后我们考虑i是第一个经过的障碍的方案数=到达i的方案数-i不是第一个经过的障碍的方案数

这也是很好算的

容斥一下即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=100010;
const int mod=1e9+7;
int n,m,k,lim;
struct blo{
	int x,y;
}c[2010];
bool cmp(const blo &A,const blo &B){
	if(A.x==B.x)return A.y<B.y;
	return A.x<B.x;
}

LL fac[maxn<<1];
LL inv[maxn<<1];
LL pow_mod(LL v,int p){
	LL tmp=1;
	while(p){
		if(p&1)tmp=tmp*v%mod;
		v=v*v%mod;p>>=1;
	}return tmp;
}
LL C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}

LL dp[2010];
void Get_DP(){
	for(int i=1;i<=k;++i){
		dp[i]=C(c[i].x+c[i].y,c[i].x);
		for(int j=1;j<i;++j){
			if(c[j].x<=c[i].x&&c[j].y<=c[i].y){
				dp[i]=dp[i]-dp[j]*C(c[i].x+c[i].y-c[j].x-c[j].y,c[i].x-c[j].x)%mod;
				if(dp[i]<0)dp[i]+=mod;
			}
		}
	}printf("%I64d\n",dp[k]);
}

int main(){
	scanf("%d%d%d",&n,&m,&k);lim=n+m-2;
	for(int i=1;i<=k;++i){
		scanf("%d%d",&c[i].x,&c[i].y);
		c[i].x--;c[i].y--;
	}
	fac[0]=1;k++;c[k].x=n-1;c[k].y=m-1;
	for(int i=1;i<=lim;++i)fac[i]=fac[i-1]*i%mod;
	inv[lim]=pow_mod(fac[lim],mod-2);
	for(int i=lim-1;i>=0;--i)inv[i]=inv[i+1]*(i+1)%mod;
	sort(c+1,c+k+1,cmp);Get_DP();
	return 0;
}

  

时间: 2024-10-13 18:28:34

codeforces #313 div1 C的相关文章

codeforces #313 div1 D

好神的题目! 首先我们运用pick定理A=S-B/2+1将要求的东西转化掉 之后分离变量,我们变成了求选取凸包面积的期望和求选取凸包在边界上的点的期望 我们先考虑求选取凸包面积的期望 如何计算凸多边形的面积,我们可以原点为划分点,计算凸包上的每个向量的叉积的和 如何计算凸包边界上的点,我们可以计算凸包上的每个向量上的点 那么我们可以考虑每个向量被计算的概率 显然p(i)-p(i+k)这个向量被计算的概率为(2^(n-k-1)-1)/(2^n-1-n-n*(n-1)/2)次 这样我们就可以O(n^

codeforces #313 div1 E

首先我们要注意到一个事情 如果一个灯塔向左覆盖,那么比他小的某个灯塔如果向左覆盖的端点大于当前塔向左覆盖的端点,他一定向右覆盖 对于当前灯塔向右覆盖也是同理 那么我们只需要记录当前覆盖到的端点就可以完成转移了 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #include<vector> using

codeforces #313 div1 B

模拟判定就可以了 判定字符串是否相等用hash来判断 QAQ 值得一提的是一开始我交的时候T了 结果我将递归的顺序调整了一下就A了 (并不知道为什么 #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef unsigned long long LL; const

codeforces #313 div1 A

捕获一只野生大水题! 首先我们知道边长为L的正三角形含有边长为1的小正三角形为L^2个 那么我们可以通过在六边形的正上,左下,右下补充正三角形使得原图形变成正三角形 然后再将补充的减去即可 #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; typedef long long

Codeforces Round 313(div1)

A题: 题目大意: 给出内角全为120度的六边形的六条边的边长,求由多少边长为1的等边三角形构成. 解题思路: 将六边形补全为一个大的等边三角形,则大的等边三角形的边长为六边形的相邻三边之和,接着减去补的部分. 补的部分是三个边长为认识3个不相邻的六边形边长的长度构成的等边三角形,边长为a的等边三角形,由a*a个边 长为1的小三角形构成. 代码: #include <iostream> #include <cstdio> #include <cstring> #incl

codeforces #305 div1 done

总算搞定了这一场比赛的题目,感觉收获蛮大 其中A,B,C都能通过自己的思考解决掉 D题思路好神,E题仔细想想也能想出来 以后坚持每两天或者一天做一场CF的div1的全套题目 除非有实在无法做出来的题目,每道题目还是都要写题解的 (我这算不算立flag? 本蒟蒻写的题解的链接: A:http://www.cnblogs.com/joyouth/p/5352953.html B:http://www.cnblogs.com/joyouth/p/5352932.html C:http://www.cn

codeforces #334 div1 603C Lieges of Legendre(博弈)

题目链接: codeforces 603C 题目大意: 有两个人做游戏,游戏规则如下: 有n堆石子,每次可以对一堆石子进行操作,如果当前石子是偶数,那么可以选择将这2*x个石子分成k堆石子数为x的石子堆,还有一种没有前提的操作是取走当前堆的一个石子,问先手赢还是后手赢,先手和后手都足够聪明的情况下. 题目分析: 首先对于这种组合游戏的题目,很容易想到利用SG函数来解.我们对于游戏的局势进行分类讨论: 当k是偶数的情况下, 我们可以知道如果要把一个偶数堆分成k个堆,相当于将局势转到一个新的组合游戏

Codeforces #594 div1 C/div2 E – Queue in the Train

题目链接:https://codeforces.com/contest/1239/problem/C 题意:火车上有n位乘客,按照1到n编号,编号为i的人会在ti分钟想去打水.水箱只能供一位乘客使用,每位乘客会使用p分钟.当一位乘客想要去打水时,他会先看编号在他前面的乘客是不是都在座位上,如果有人没在座位上,他会坐下继续等待,否则他会去排队打水.当某一时刻有几位乘客同时想要打水时,编号最小的乘客会前去打水,其他人会坐下继续等待,计算每位乘客打完水的时间. 做法:模拟.按照题意模拟即可,具体实现见

codeforces#426(div1) B - The Bakery (线段树 + dp)

题意:把 n 个数划分成 m 段,要求每组数不相等的数的数量最大之和. 思路: dp方程 : dp[i][j] = max( dp[k][j-1] + v(k, i) );( j<=k<i , k = j, j+1, +...+ i-1) dp[i][j]表示第 i 个数分到第 j 段的最大值. v(k, i) 表示k~i中不同数的个数,此处用hash记录每个数上一次出现的位置,从上一次出现的位置到当前位置的 dp[i][j-1] 值均可+1. 此时时间复杂度 O(n*m*log(n)). 线