BZOJ4767 兩雙手
阿新 • • 發佈:2019-03-26
tdi esp 順序 sum www. for lse tor getchar
BZOJ4767 兩雙手
題面:BZOJ
解析
容斥水題。先解出走到結束點和禁止點的步數(不難發現這個步數是唯一的)。然後去掉絕對不會走到的禁止點,現在考慮容斥去除禁止點的影響,不難想到+-1的容斥方法,但是怎麽確定貢獻呢?對於至少走\(i\)個禁止點,方案數就是強制走\(i\)個點的方案數,其後再隨意分配即可。這樣做很難做,不妨變換枚舉順序,改為枚舉每一個點作為最後一個被走到的禁止點,這樣可以\(O(n^2)\)的預處理方案數,在中途+-1即可。我也不知道我是怎麽亂搞過的
代碼
#include<cstdio> #include<algorithm> #define N 505 using namespace std; const int P=1e9+7,__=1e6; inline int In(){ char c=getchar(); int x=0,ft=1; for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1; for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return x*ft; } inline int max(int a,int b){ return a>b?a:b; } int Ex,Ey,Ax,Ay,Bx,By,A,B,t[N],n,lim,qc=0,ans=0,g[N],fac[__],inv[__]; struct Q{ int a,b; bool operator < (const Q& t) const { return a==t.a?b<t.b:a<t.a; } }q[N]; inline int power(int x,int k){ int s=1,t=x; for(;k;k>>=1,t=1ll*t*t%P) if(k&1) s=1ll*s*t%P; return s; } inline void Sol(int x,int y,int& t1,int& t2){ if((Bx*y-By*x)%(Ay*Bx-Ax*By)==0&&(Ax*y-Ay*x)%(By*Ax-Bx*Ay)==0) t1=(Bx*y-By*x)/(Ay*Bx-Ax*By),t2=(Ax*y-Ay*x)/(By*Ax-Bx*Ay); else t1=2e9,t2=2e9; } inline int f(int i,int j){ return 1ll*fac[i+j]*inv[i]%P*inv[j]%P; } int main(){ Ex=In(); Ey=In(); n=In(); Ax=In(); Ay=In(); Bx=In(); By=In(); Sol(Ex,Ey,A,B); if(A==2e9){ printf("%d\n",0); return 0;} lim=A+B; fac[0]=1; for(int i=1;i<=lim;++i) fac[i]=1ll*fac[i-1]*i%P; inv[lim]=power(fac[lim],P-2); for(int i=lim-1;~i;--i) inv[i]=1ll*inv[i+1]*(i+1)%P; for(int i=1,a,b,Sx,Sy;i<=n;++i){ Sx=In(); Sy=In(); Sol(Sx,Sy,a,b); if(a<=A&&b<=B) q[++qc].a=a,q[qc].b=b; } n=qc; sort(q+1,q+1+n); for(int i=1;i<=n;++i){ g[i]=f(q[i].a,q[i].b); for(int j=1;j<i;++j) if(q[j].a<=q[i].a&&q[j].b<=q[i].b) g[i]=(g[i]-1ll*g[j]*f(q[i].a-q[j].a,q[i].b-q[j].b)%P+P)%P; } ans=f(A,B); for(int i=1,sum;i<=n;++i) ans=(ans+1ll*(P-1)*f(A-q[i].a,B-q[i].b)%P*g[i]%P)%P; printf("%d\n",ans); return 0; }
BZOJ4767 兩雙手