CF#313-E. Gerald and Giant Chess-dp+组合数学

一开始想用容斥原理 。。后来发现有些地方处理有些麻烦。。。


用dp的话,dp[i]并表示 从起点到 障碍i 所有的合法路径数

hint: 从起点到点 x,y的所有路径方案为  C(x-1+y-1,x-1) (要减一是因为本题是格点)


那么 对点i,把所有在点i的左上方的点称为j

dp[i]= C(x-1+y-1,x-1);

对所有j点:dp[i]-=dp[j]*get_dis(i,j) 

把第q+1个点设为(n,m)即可


取组合要用到费马小定理,预处理好阶乘




#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

__int64 dp[2005] ;
__int64 mod=1e9+7;
__int64 fast_m(__int64 a,__int64 b)  
{  
    __int64 x,ans=1;  
    x=a;  
    while(b)  
    {  
        if (b&1)  
            ans=(ans*x)%mod;  
        x=(x*x)%mod;  
        b/=2;  
    }  
    return ans;  
} 
__int64 fac[200010];  
inline __int64 cal(__int64 x,__int64 y)  
{   
    return (fac[x]*fast_m(fac[y]*fac[x-y]%mod,mod-2))%mod;   
} 
struct node
{
	__int64 x,y;
};
node tm[2005];
bool cmp(node &a,node &b)
{
	if (a.x!=b.x)
		return a.x<b.x;
	else
		return a.y<b.y;
} 
int main()
{
	__int64 x,y,i,j;
	
	__int64 n,m,q;
	scanf("%I64d%I64d%I64d",&n,&m,&q);
    fac[0]=1;  
	for(  i=1;i<=2e5;i++)    
		fac[i]=fac[i-1]*i%mod;   
	for (i=1;i<=q;i++)
	{		
		scanf("%I64d%I64d",&tm[i].x,&tm[i].y); 
	} 
	sort(tm+1,tm+1+q,cmp);
	tm[q+1].x=n;
	tm[q+1].y=m;
	__int64 add=0;
	for (i=1;i<=q+1;i++)	
	{
		dp[i]=cal(tm[i].x+tm[i].y-2,tm[i].x-1);
		for (j=1;j<i;j++)
		{
		if (tm[j].x<=tm[i].x&&tm[j].y<=tm[i].y)
		{
			dp[i]= dp[i]-cal(tm[i].x+tm[i].y-tm[j].x-tm[j].y,tm[i].y-tm[j].y)*(dp[j])   %mod; 
			dp[i]=(dp[i]+mod)%mod;	
		}
		}
	}
	__int64 ans=dp[q+1];
	while(ans<0) 
		ans+=mod;
	printf("%I64d\n",(ans) %mod);
	
	
	return 0;
	
}



你可能感兴趣的:(CF#313-E. Gerald and Giant Chess-dp+组合数学)