• 【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
    ",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
    ");
     77     //printf("%d %d
    ",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
    ",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
    ",solve());
    200     }      
    201     return 0;
    202 }
    203      
  • 相关阅读:
    Android多屏幕适配
    android应用签名详解
    内部类与静态内部类详解
    SpringBoot整合Spring Retry实现重试机制
    行为型模式之模板方法模式
    行为型模式之操作复杂对象结构(访问者模式)
    行为型模式之算法的封装与切换(策略模式)
    行为型模式之处理对象的多种状态及其相互转换(状态模式)
    行为型模式之对象间的联动(观察者模式)
    行为型模式之撤销功能的实现(备忘录模式)
  • 原文地址:https://www.cnblogs.com/myx12345/p/6755076.html
Copyright © 2020-2023  润新知