【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
null