题目:A Simple Chess
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794
题意:起始点(1,1),要到达(n,m),下一步(x2,y2),这一步(x1,y1),需满足(x2-x1)^2 +(y2-y1)^2 = 5,且 x2>x1 、y2>y1。中间还有r 个障碍点,问最终有多少种方法到达(n,m)。n、m高达10^18,r最多100。
思路:
大概画一下图,就可以知道从(1,1)到(n,m)的方法数是一个组合数。
现在问题是障碍点,我们可以先计算(1,1)到每个障碍点的方法数sum(先当做这个障碍点不受其他障碍点影响),然后对障碍点排序,排序方法是从内圈到外圈( 其实可到达的点会形成无数的同心圆 ),然后两重循环,判断这个障碍点p1会对哪些障碍点(和终点)p2照成影响,受影响的障碍点sum减去影响数(p1.sum*组合数(这个组合数是从p1到p2的方法数)),逐层排查。就可以计算出(n,m)还剩下多少种方法可到达。
难点就在于大组合数取模了...我事先也没有准备模板,临时盗用别人的。。
AC代码:
1 #include<stdio.h>
2 #include<string.h>
3 #include<algorithm>
4 using namespace std;
5 #define N 150000
6 typedef long long LL;
7 struct Node
8 {
9 LL x,y,sum;
10 bool friend operator < (Node a,Node b)
11 {
12 return a.x+a.y<b.x+b.y;
13 }
14 };
15 const LL p=110119;
16 LL fac[N];
17 void init()
18 {
19 int i;
20 fac[0] =1;
21 for(i =1; i <= p; i++)
22 fac[i] = fac[i-1]*i%p;
23 }
24 LL pow(LL a, LL b)
25 {
26 LL tmp = a % p, ans =1;
27 while(b)
28 {
29 if(b &1) ans = ans * tmp % p;
30 tmp = tmp*tmp % p;
31 b >>=1;
32 }
33 return ans;
34 }
35 LL C(LL n, LL m)
36 {
37 if(m>n)return 0;
38 return fac[n]*pow(fac[m]*fac[n-m],p-2)%p;
39 }
40 LL cfun(LL n, LL m)
41 {
42 if(m ==0) return 1;
43 else return (C(n%p,m%p)*cfun(n/p, m/p))%p;
44 }
45 Node a[110];
46 int ao;
47
48 bool check(Node a,Node b)
49 {
50 if( (b.x+b.y-a.x-a.y) % 3 != 0 ) return false;
51 LL t=b.y-a.y;
52 if(b.x-a.x<=2*t && 2*(b.x-a.x) >=t ) return true;
53 return false;
54 }
55 LL solve(Node a,Node b)
56 {
57 if(b.x==a.x && b.y==a.y) return a.sum;
58 if( !check(a,b) ) return 0;
59 LL xia=(b.x+b.y-a.x-a.y)/3;
60 LL shang=(b.y-a.y)-xia;
61 return (a.sum*cfun(xia,shang))%p;
62 }
63
64 int main()
65 {
66 init();
67 LL n,m;
68 int r,cas=1;
69 while(scanf("%I64d%I64d%d",&n,&m,&r)!=EOF)
70 {
71 Node s,t;
72 s.sum=1;
73 s.x=0,s.y=0;
74 n--,m--;
75 t.x=n,t.y=m;
76 t.sum=solve(s,t);
77 ao=0;
78 for(int i=0;i<r;i++)
79 {
80 scanf("%I64d%I64d",&a[ao].x,&a[ao].y);
81 a[ao].x--,a[ao].y--;
82 if( !check(s,a[ao]) ) continue;
83 ao++;
84 }
85 for(int i=0;i<ao;i++)
86 {
87 a[i].sum=solve(s,a[i]);
88 }
89 sort(a,a+ao);
90 for(int i=0;i<ao;i++)
91 {
92 for(int j=i+1;j<ao;j++)
93 {
94 if( check(a[i],a[j]) )
95 {
96 a[j].sum=(a[j].sum-solve(a[i],a[j])+p)%p;
97 }
98 }
99 t.sum=(t.sum-solve(a[i],t)+p)%p;
100 }
101 printf("Case #%d: ",cas++);
102 printf("%I64d
",t.sum);
103 }
104 return 0;
105 }