【CodeChef】KNGHTMOV(方案数DP)

题意:

考虑一张无限大的方格棋盘。我们有一个“骑士”,它必须从(0,0)格开始,按照如下规则,移动至(X,Y)格:每一步,它只能从(u,v)格移动至(u+Ax,v+Ay)或者(u+Bx,v+By)。注意,该规则可能不同于国际象棋中骑士的移动规则。

此外,棋盘上有K个障碍格,骑士不能进入这些格子。

你的任务是计算骑士有多少种到达指定位置的方案。我们认为两种方案不同,当且仅当它们的步数不同,或者存在某个i使得两种方案中,骑士在第i步到达的格子不同。注意,骑士在到达(X,Y)格后还可能继续移动。

对每组数据,输出移动方案数模1000000007(10^9+7)的值。如果有无穷多种方案,输出-1.

所有坐标的绝对值不超过500

(0,0)不是障碍格

(X,Y)不是障碍格

1<=T<=5

对于40%的数据,0<=K<=5

对于100%的数据,0<=K<=15

思路:

向量贡献部分的dp 

dp[i][j]表示走i步,当前在位置j的方案数,因为所有向量都已经被压缩成了1维

 详细翻译题解:http://blog.csdn.net/wmdcstdio/article/details/48676173
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<map>
  8 #include<set>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef unsigned int uint;
 14 typedef unsigned long long ull;
 15 typedef pair<int,int> PII;
 16 typedef vector<int> VI;
 17 #define fi first
 18 #define se second 
 19 #define MP make_pair
 20 #define N   1100000
 21 #define M   1100
 22 #define eps 1e-8
 23 #define MOD 1000000007
 24 #define pi  acos(-1)
 25 
 26 class Point
 27 {
 28     public: 
 29     int x,y;
 30 };
 31 
 32 ll dp[M*2+1][M*2+1];
 33 bool vis[M*2+1][M*2+1];
 34 bool flag[M*2+1];
 35 ll fac[N],inv[N];
 36 Point b[20],A,B,d;
 37 ll f[20];
 38 int K;
 39 
 40 int read()
 41 { 
 42    int v=0,f=1;
 43    char c=getchar();
 44    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
 45    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 46    return v*f;
 47 }
 48 
 49 void add(ll &a,ll &b)
 50 {
 51     if(a==-1||b==-1) a=-1;
 52      else a=(a+b)%MOD;
 53 }
 54  
 55 bool depend(Point &a,Point &b) //线性相关 
 56 {
 57     //printf("%d %d %d %d\n",a.x,b.y,a.y,b.x); 
 58     return a.x*b.y==a.y*b.x;
 59 }
 60 
 61 bool operator < (Point &a,Point &b)
 62 {
 63     return a.x+a.y<b.x+b.y;
 64 }
 65 
 66 void swap_xy()
 67 {
 68     swap(A.x,A.y);
 69     swap(B.x,B.y);
 70     swap(d.x,d.y);
 71     for(int i=1;i<=K;i++) swap(b[i].x,b[i].y);
 72 }
 73 
 74 int solve_depend()
 75 {
 76     //printf("YES\n");
 77     //printf("%d %d\n",d.x,d.y);
 78     if(!depend(A,d)||!depend(B,d)) return 0;
 79     //A,B中可能有0
 80     if(!A.x&&!A.y&&!B.x&&!B.y) 
 81     {
 82         if(!d.x&&!d.y) return -1;
 83         return 0;
 84     }
 85     if(!A.x)
 86     {
 87         if(A.y) swap_xy();
 88          else if(B.x) swap(A,B);
 89           else
 90           {
 91                   swap(A,B);
 92                   swap_xy();
 93           }    
 94     }
 95     memset(dp,0,sizeof(dp));
 96     memset(vis,0,sizeof(vis));
 97     memset(flag,0,sizeof(flag));
 98     for(int i=1;i<=K;i++)
 99      if(depend(b[i],A)&&depend(b[i],B)) flag[b[i].x+M]=1;
100     if((!A.x&&!A.y)||(!B.x&&!B.y)) dp[0][M]=-1;
101      else dp[0][M]=1;
102     vis[0][M]=true; 
103     ll ans=0;
104     for(int i=0;i<M*2;i++)
105     {
106         for(int j=-M;j<=M;j++)
107         {
108             int v=j+M;
109             if(!flag[v])    //无障碍 
110             {
111                 if(!vis[i][v]) continue;
112                 if(j>500||j<-500||i>1000) dp[i][v]=-1; //若能绕回dest必定有无数种,若回不来那-1也没用
113                 if(v+A.x>=0&&v+A.x<=2*M)    //A
114                 {
115                     add(dp[i+1][v+A.x],dp[i][v]);
116                     vis[i+1][v+A.x]=true;
117                 }
118                 if(A.x!=B.x&&v+B.x>=0&&v+B.x<=2*M) //B
119                 {
120                     add(dp[i+1][v+B.x],dp[i][v]);
121                     vis[i+1][v+B.x]=true;
122                 }
123             }
124         }
125         add(ans,dp[i][d.x+M]);
126     }
127     return ans;
128 }
129 
130 bool change(Point &p)
131 {
132     int k=A.y*B.x-A.x*B.y;
133     int a=p.y*B.x-p.x*B.y;
134     int b=p.x*A.y-p.y*A.x;
135     //printf("%d %d %d\n",k,a,b);
136     if(a%k||b%k) return false;
137     p.x=a/k; p.y=b/k;
138     return true;
139 }
140 
141 ll C(int x,int y)
142 {
143     return fac[x]*inv[y]%MOD*inv[x-y]%MOD;
144 }
145 
146 ll calc(Point &a,Point &b)
147 {
148     int x=b.x-a.x;
149     int y=b.y-a.y;
150     if(x<0||y<0) return 0;
151     return C(x+y,x);
152 }
153 
154 int solve_independ()
155 {
156     if(!change(d)) return 0;    //终点在变换后不是整点
157     if(d.x<0||d.y<0) return 0;     //终点在变换后不是整点
158     int n=0;
159     for(int i=1;i<=K;i++)     //障碍变换 
160      if(change(b[i]))
161       if(b[i].x>=0&&b[i].y>=0) b[++n]=b[i];
162     sort(b+1,b+n+1);     //障碍排序 
163     Point O=(Point){0,0};
164     ll ans=calc(O,d);
165     
166     for(int i=1;i<=n;i++)
167     {
168         f[i]=calc(O,b[i]);
169         for(int j=1;j<i;j++) 
170          f[i]=(f[i]-f[j]*calc(b[j],b[i])%MOD)%MOD;
171         ans=(ans-f[i]*calc(b[i],d)%MOD)%MOD;
172     }
173     ans=(ans%MOD+MOD)%MOD;
174     return ans;
175 }
176     
177 int solve()
178 {
179     if(depend(A,B)) return solve_depend();
180     else return solve_independ();
181 }
182 
183 int main()
184 {
185     //freopen("1.in","r",stdin);
186     //freopen("1.out","w",stdout);
187     fac[0]=1;
188     for(int i=1;i<=N-1;i++) fac[i]=fac[i-1]*i%MOD;
189     inv[0]=inv[1]=1;
190     for(int i=2;i<=N-1;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
191     for(int i=1;i<=N-1;i++) inv[i]=inv[i-1]*inv[i]%MOD; 
192     int cas;
193     scanf("%d",&cas);
194     while(cas--)
195     {
196         scanf("%d%d%d",&d.x,&d.y,&K);
197         scanf("%d%d%d%d",&A.x,&A.y,&B.x,&B.y);
198         for(int i=1;i<=K;i++) scanf("%d%d",&b[i].x,&b[i].y);
199         printf("%d\n",solve());
200     }      
201     return 0;
202 }
203      

 

posted on 2017-04-24 08:33  myx12345  阅读(215)  评论(0编辑  收藏  举报

导航