zoukankan      html  css  js  c++  java
  • 【BZOJ4767】两双手(动态规划,容斥)

    【BZOJ4767】两双手(动态规划,容斥)

    题面

    BZOJ

    题解

    发现走法只有两种,并且两维坐标都要走到对应的位置去。
    显然对于每个确定的点,最多只有一种固定的跳跃次数能够到达这个点。
    首先对于每个点都计算出两种跳跃方法的次数。
    然后按照跳跃次数排序。
    显然只可能从跳跃次数少的跳跃到跳跃次数多的点。
    考虑(f[i])表示到达第(i)个点且不经过前面任何一个障碍点的方案数。
    (f[i]=C_{x+y}^x),其中(x,y)表示两种方法跳跃的次数。
    然后容斥减去经过前面任何一个点的方案数就好了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 1111111
    #define MOD 1000000007
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int Ex,Ey,Ax,Ay,Bx,By,n;
    struct Node{int x,y;}p[MAX];
    bool cmp(Node a,Node b){if(a.x==b.x)return a.y<b.y;return a.x<b.x;}
    int jc[MAX],jv[MAX],inv[MAX],f[MAX];
    int C(int n,int m){if(n<m)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
    void Calc(int &x,int &y)
    {
    	ll a1,a2,b1,b2;
    	a1=x*By-y*Bx;a2=Ax*By-Ay*Bx;
    	b1=x*Ay-Ax*y;b2=Bx*Ay-Ax*By;
    	if(a2==0||b2==0){x=-1;y=-1;return;}
    	if((a1/a2)*a2!=a1||(b1/b2)*b2!=b1){x=-1;y=-1;return;}
    	x=a1/a2;y=b1/b2;
    }
    int main()
    {
    	Ex=read();Ey=read();n=read();
    	Ax=read(),Ay=read();Bx=read();By=read();
    	Calc(Ex,Ey);
    	for(int i=1;i<=n;++i)
    	{
    		p[i].x=read(),p[i].y=read();
    		Calc(p[i].x,p[i].y);
    		if(p[i].x<0||p[i].y<0||p[i].x>Ex||p[i].y>Ey)--n,--i;
    	}
    	p[++n]=(Node){Ex,Ey};sort(&p[1],&p[n+1],cmp);
    	jc[0]=jv[0]=inv[0]=inv[1]=1;
    	for(int i=1;i<MAX;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    	for(int i=2;i<MAX;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<MAX;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    	for(int i=1;i<=n;++i)
    	{
    		f[i]=C(p[i].x+p[i].y,p[i].x);
    		if(!f[i])continue;
    		for(int j=1;j<i;++j)
    			f[i]=(f[i]-1ll*f[j]*C(p[i].x-p[j].x+p[i].y-p[j].y,p[i].x-p[j].x)%MOD+MOD)%MOD;
    	}
    	printf("%d
    ",f[n]);
    	return 0;
    }
    
    
  • 相关阅读:
    7.25
    7.24
    7.23
    7.22
    输入语句/条件运算符
    flowLayoutPanel1设置内容随着鼠标滚动而滚动
    dataGridView读取xml文件
    读文本内容 写入文本内容 创建复制文本
    cmd.ExecuteScalar 和配置连接设置
    $.ajax async同步加载
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9254048.html
Copyright © 2011-2022 走看看