题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794
可以储存所有的点,再以从上到下,从左至右的顺序进行排序。
对于每个点i,有dp[i] = dp[i] - sum(dp[j]*Lucas(point[j])) (0 <= j < i)
因此可以得到所有的点,对于不包括前i个点的路线数目。
那么答案ans = sum(dp[i]) (0 <= i < r)。
最后注意要对无影响的点进行去重。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL p = 110119;
struct Point{
LL x, y;
bool operator < (const Point &A) const{
if(x == A.x)
return y < A.y;
return x < A.x;
}
}point[110];
LL dp[110];
LL PowMod(LL a,LL b,LL MOD){
LL ret=1;
while(b){
if(b&1) ret=(ret*a)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return ret;
}
LL fac[110219];
LL Get_Fact(LL p)
{
fac[0]=1;
for(int i=1;i<=p;i++)
fac[i]=(fac[i-1]*i)%p;
}
LL Lucas(LL n,LL m,LL p){
LL ret=1;
while(n&&m){
LL a=n%p,b=m%p;
if(a<b) return 0;
ret=((ret*fac[a]%p)*PowMod(fac[b]*fac[a-b]%p,p-2,p))%p;
n/=p;
m/=p;
}
return ret;
}
bool check(LL x, LL y){
if((x+y-2)%3 != 0)
return false;
if(min(x, y) > (x+y)/3)
return true;
return false;
}
int main(){
int r, cnt, CASE = 0;
LL n, m, x, y;
Get_Fact(p);
while(cin >> n >> m >> r){
cnt = 0;
for(int i = 0; i < r; i++){
scanf("%I64d %I64d", &x, &y);
if(check(x, y)){
point[cnt].x = x;
point[cnt++].y = y;
}
}
if(!check(n, m) || (point[cnt-1].x == n && point[cnt-1].y == m)){
printf("Case #%d: 0\n", ++CASE);
continue;
}
sort(point, point + cnt);
point[cnt].x = n;
point[cnt].y = m;
for(int i = 0; i <= cnt; i++){
LL u = (LL)((point[i].x+point[i].y-2)/3);
LL v = (LL)((2*point[i].x-point[i].y-1)/3);
dp[i] = Lucas(u, v, p);
for(int j = 0; j < i; j++){
if(point[i].x >= point[j].x && point[i].y >= point[j].y){
x = point[i].x-point[j].x+1;
y = point[i].y-point[j].y+1;
if(!check(x, y))
continue;
u = (LL)((x+y-2)/3);
v = (LL)((2*x-y-1)/3);
dp[i] -= (dp[j]*Lucas(u, v, p)%p);
dp[i] = (dp[i]+p)%p;
}
}
}
printf("Case #%d: %I64d\n", ++CASE, dp[cnt]);
}
return 0;
}