[数学][dp] Jzoj P4236 登山
Posted comfortable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[数学][dp] Jzoj P4236 登山相关的知识,希望对你有一定的参考价值。
题解
- 题目大意:给定c个不能走的点,问从(0,0)到(n,n)不经过不能走的点和y>x的点的路径数量
- 首先30%的数据,很容易直接n^2dp就好了f[i][j]=f[i-1][j]+f[i][j-1]
- 考虑一下反过来做,ans=全部的路径-不合法的路径
- 显然我们可知道从(0,0)到(x,y)的无限制的路径数=C(x+y,x)
- 那么现在就来考虑一下不合法的路径数
- 先考虑一下没有山脊限制的情况,设f[i]表示走到第i个路障的方案数(不经过其他的路障)
- 那么f[i]可以从其他路障的f[j]转移容斥过来得到,就是在经过第j个路障时容斥掉不合法的路径数
- 再考虑一下有山脊的限制,对于从(a,b)要走到(c,d),那么不碰到对称轴的方案数=所有走到(c,d)的方案数-所有走到(c,d)关于对称轴对称的对称点的方案数
- 就按照上面的方法做就好了,完结(撒花)
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #define ll long long 5 using namespace std; 6 const int N=100010,mo=1e9+7; 7 int n,c; 8 ll f[N],g[N],fac[2*N],ny[2*N],r; 9 struct edge { ll x,y; }a[N]; 10 ll ksm(ll a,ll b) { for (r=1;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r; } 11 ll C(int b,int a) 12 { 13 if (a==0||a==b) return 1; 14 return ((fac[b]*ny[a])%mo*ny[b-a])%mo; 15 } 16 bool cmp(edge a,edge b) { return a.x<b.x||a.x==b.x&&a.y<b.y; } 17 ll calc(int i,int j) 18 { 19 int x=a[j].x-a[i].x,y=a[j].y-a[i].y; 20 if (x<0||y<0) return 0; 21 if (a[j].y-1-a[i].x<0||a[j].x+1-a[i].y<0) return C(x+y,x); 22 return (C(x+y,x)-C(x+y,a[j].y-1-a[i].x)+mo)%mo; 23 } 24 int main() 25 { 26 scanf("%d%d",&n,&c); 27 for (int i=1;i<=c;i++) scanf("%d%d",&a[i].x,&a[i].y); 28 fac[1]=ny[1]=1; for (int i=2;i<=n*2;i++) fac[i]=(fac[i-1]*i)%mo,ny[i]=ksm(fac[i],mo-2); 29 a[c+1].x=n,a[c+1].y=n,sort(a,a+c+1,cmp); 30 for (int i=1;i<=c+1;i++) 31 { 32 for (int j=1;j<i;j++) (g[i]+=f[j]*calc(j,i)%mo)%=mo; 33 f[i]=(calc(0,i)-g[i]+mo)%mo; 34 } 35 printf("%lld",f[c+1]); 36 }
以上是关于[数学][dp] Jzoj P4236 登山的主要内容,如果未能解决你的问题,请参考以下文章
[DP][数学]JZOJ 3318 Brunhilda的生日
Jzoj 3056NOIP2012模拟10.27容斥DP数学数字