# BZOJ4767：两双手 （组合数学+DP+容斥原理）

DP 同时被 3 个专栏收录
34 篇文章 1 订阅
23 篇文章 0 订阅
5 篇文章 0 订阅

f[i]=g(0,i)j.xi.x,j.yi.yf[j]g(j,i) f [ i ] = g ( 0 , i ) − ∑ j . x ≤ i . x , j . y ≤ i . y f [ j ] ∗ g ( j , i )

CODE：

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;

const int maxn=550;
const int maxm=1000000;
const long long M=1000000007;
typedef long long LL;

struct data
{
int X,Y;
} point[maxn];
LL f[maxn];
int cnt;

LL fac[maxm];
LL nfac[maxm];

int tx,ty;
int ax,ay,bx,by,tp;
int n;

bool Work(int &u,int &v)
{
int q=u*ay-v*ax;
if ( !tp || q%tp ) return false;
q/=tp;
int p;
if (ax)
{
p=u-q*bx;
if (p%ax) return false;
p/=ax;
}
else
{
if (!ay) return false;
p=v-q*by;
if (p%ay) return false;
p/=ay;
}
if ( p<0 || q<0 ) return false;
u=p;
v=q;
return true;
}

bool Comp(data x,data y)
{
return x.X<y.X || ( x.X==y.X && x.Y<y.Y );
}

LL C(int nn,int mm)
{
LL val=fac[nn];
val=val*nfac[nn-mm]%M;
val=val*nfac[mm]%M;
return val;
}

int main()
{
freopen("hands.in","r",stdin);
freopen("hands.out","w",stdout);

scanf("%d%d%d",&tx,&ty,&n);
scanf("%d%d%d%d",&ax,&ay,&bx,&by);

tp=bx*ay-by*ax;
if ( !Work(tx,ty) )
{
printf("0\n");
return 0;
}

for (int i=1; i<=n; i++)
{
int u,v;
scanf("%d%d",&u,&v);
if ( !Work(u,v) ) continue;
if ( u>tx || v>ty ) continue;
cnt++;
point[cnt].X=u;
point[cnt].Y=v;
}

cnt++;
point[cnt].X=tx;
point[cnt].Y=ty;
sort(point+1,point+cnt+1,Comp);

fac[0]=1;
for (LL i=1; i<maxm; i++) fac[i]=fac[i-1]*i%M;
nfac[0]=nfac[1]=1;
for (LL i=2; i<maxm; i++)
{
LL x=M/i,y=M%i;
nfac[i]=M-x*nfac[y]%M;
}
for (int i=1; i<maxm; i++) nfac[i]=nfac[i-1]*nfac[i]%M;

for (int i=1; i<=cnt; i++)
{
f[i]=C(point[i].X+point[i].Y,point[i].X);
for (int j=1; j<i; j++)
{
int dx=point[i].X-point[j].X;
int dy=point[i].Y-point[j].Y;
LL temp=0;
if ( dx>=0 && dy>=0 ) temp=f[j]*C(dx+dy,dx)%M;
f[i]=(f[i]-temp+M)%M;
}
}
printf("%I64d\n",f[cnt]);

return 0;
}
• 0
点赞
• 0
评论
• 0
收藏
• 一键三连
• 扫一扫，分享海报

05-21 599
04-19 31

09-11 128
04-10 371
10-25 156
03-11 749
03-07 992
03-22 251
06-07 136
09-24 47
06-01 184
07-02 249
03-08 43
02-11 161
12-08 1876
08-01
©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。