CF #313 (Div. 2) E. Gerald and Giant Chess (dp+Lucas组合计数)
2016-08-06 12:59
363 查看
题目链接
在一个n*m的网格上从(1,1)出发到(n,m)每次只能往右或者往下一步,同时还给出k个坏点,坏点是不可以走到的,问有多少的方式到大(n,m).
经典的题目,记录下来学习,假设目的地是一个特殊的坏点,那么就可以设
dp[i]:表示到达第i个坏点且不经过其他的坏点的方案数。
再看一下这个问题,从(0,0)点到(2,4)点的走法有几个?,答案就是C(2+4,2)或者C(2+4,4)。解释一下,因为每次只能往右一步,或者往下一步,所以,走法就是总的步数中选择往右走的步数次数,或者是往下走的步数的次数。
那么状态转移方程就是dp[i]=C(x[i]+y[i],x[i]) - sum{dp[j]*C(dx+dy,dx) }。其中的dx,dy是点i 到 点j 的 距离差值。
然后再来说一说细节,因为题目的要求也就是只能往右下走,那么我们可以给点排序,那么状态转移方程的j就是在i之前的点了,然后再把终点加入进来,那么答案就是第k个点的方案数,即是dp[k].
最后就是关于组合数的计算了,我们可以预处理出阶乘的逆元,然后就可以计算了,here
在一个n*m的网格上从(1,1)出发到(n,m)每次只能往右或者往下一步,同时还给出k个坏点,坏点是不可以走到的,问有多少的方式到大(n,m).
经典的题目,记录下来学习,假设目的地是一个特殊的坏点,那么就可以设
dp[i]:表示到达第i个坏点且不经过其他的坏点的方案数。
再看一下这个问题,从(0,0)点到(2,4)点的走法有几个?,答案就是C(2+4,2)或者C(2+4,4)。解释一下,因为每次只能往右一步,或者往下一步,所以,走法就是总的步数中选择往右走的步数次数,或者是往下走的步数的次数。
那么状态转移方程就是dp[i]=C(x[i]+y[i],x[i]) - sum{dp[j]*C(dx+dy,dx) }。其中的dx,dy是点i 到 点j 的 距离差值。
然后再来说一说细节,因为题目的要求也就是只能往右下走,那么我们可以给点排序,那么状态转移方程的j就是在i之前的点了,然后再把终点加入进来,那么答案就是第k个点的方案数,即是dp[k].
最后就是关于组合数的计算了,我们可以预处理出阶乘的逆元,然后就可以计算了,here
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<cstdlib> #include<vector> using namespace std; #define cl(a,b) memset(a,b,sizeof(a)) #define LL long long #define pb push_back #define gcd __gcd #define For(i,j,k) for(int i=(j);i<k;i++) #define lowbit(i) (i&(-i)) #define _(x) printf("%d\n",x) const int maxn = 2e5+200; const int inf = 1 << 28; LL p = 1e9+7; int n,m,k; LL fac[maxn],inv[maxn]; LL qsm(LL a, LL b){ LL ans = 1; while(b){ if(b&1)ans = ans*a%p; a = a*a%p; b>>=1; } return ans%p; } LL C(LL n,LL m){ if(m>n)return 0; LL ans = fac ; ans = ans*inv[m]%p * inv[n-m] % p; return ans; } void init(){ fac[0]=inv[0]=1; for(int i=1;i<maxn;i++){ fac[i] = fac[i-1]*i%p; inv[i]=qsm(fac[i],p-2)%p; } } LL dp[maxn]; pair<LL,LL> point[maxn]; int main(){ init(); scanf("%d%d%d",&n,&m,&k); for(int i=0;i<k;i++){ scanf("%lld%lld",&point[i].first,&point[i].second); point[i].second--;point[i].first--; } point[k].first=n-1; point[k++].second=m-1; sort(point,point+k); for(int i=0;i<k;i++){ LL sum = 0; for(int j=0;j<i;j++){ LL dx = point[i].first - point[j].first; LL dy = point[i].second - point[j].second; if(dx<0||dy<0)continue; sum=dp[j]*C(dx+dy,dx)%p+sum%p; } dp[i]=C(point[i].first+point[i].second, point[i].first)-sum; dp[i] = (dp[i] + p) % p; } printf("%lld\n",(dp[k-1]+p)%p); return 0; }
相关文章推荐
- Codeforces Round #313 (Div. 2) E. Gerald and Giant Chess (Lucas + dp)
- Codeforces #313 (Div. 1) C. Gerald and Giant Chess dp 组合数 逆元
- codeforces 560 E. Gerald and Giant Chess (dp+lucas定理,求大组合数 mod p,p为质数)
- Codeforces Round #313 (Div. 2) E. Gerald and Giant Chess 定理Lucas求大组合数
- Codeforces Round #313 (Div. 2)E. Gerald and Giant Chess(Lucas定理+dp)
- dp - Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess
- Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess DP
- Codeforces Round #313 (Div. 1) C - Gerald and Giant Chess dp
- Codeforces 560E Gerald and Giant Chess 组合数学+DP
- Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess DP
- dp - Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess
- 【CF559C】 Gerald and Giant Chess(计数,方案数DP,数论)
- Codeforces 560 E. Gerald and Giant Chess (dp,组合数学)
- Code Forces 559 C. Gerald and Giant Chess(组合数学+dp)
- 【CodeForces】559C - Gerald and Giant Chess(dp & 逆元 & 容斥原理)
- Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess
- [CodeForces] Round #313 Div 2 E / Div 1 C Gerald and Giant Chess 不用容斥的递推组合数学
- Codeforces 559C Gerald and Giant Chess(组合数学+DP)
- Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess(DP+组合数取模)(好题)
- codeforces(559C)--C. Gerald and Giant Chess(组合数学)