• 上学路线


     时间限制: 1 s空间限制: 64000 KB

    题目描述 Description

    因为是学生,所以显然小A每天都要上学。小A所在的城市的道路构成了一个n*m的网格,每条道路都是可以单向通行的。小A家在点(1,1),学校在点(n,m)。在不移出边界的情况下,小A可以从点(x,y)移动到点(x+1,y)或(x,y+1)。为了追求新鲜感,小A经常走不同的道路去上学。有一天,小A突发奇想:到底他可以有多少种不同的上学路线呢?

    输入描述 Input Description

    两个正整数n,m,意义如前所述。

    输出描述 Output Description

    一个正整数,小A的上学路线数量。

    样例输入 Sample Input

    2 3

    样例输出 Sample Output

    3

    数据范围及提示 Data Size & Hint

    对于30%的数据,n,m<=100;

    对于100%的数据,n+m<=40000.

    是不是感覺這道題很水啊(才怪呢,有沒有看數據範圍)。
    
    搜索代碼(10分):
    
    #include<cstdio>
    int n,m,ans;
    void dfs(int x,int y){
    if(x==n&&y==m){++ans;return;}
    if(y<m) dfs(x,y+1);
    if(x<n) dfs(x+1,y);
    }
    int main(){
    scanf("%d%d",&n,&m);
    dfs(1,1);
    printf("%d
    ",ans);
    return 0;
    }
    
    對的,這是個DP題。
    
    數據:
    
    1  1  1   1   1    1    1     1     1     1 
    1  2  3   4   5    6    7     8     9    10 
    1  3  6  10  15   21   28    36    45    55 
    1  4 10  20  35   56   84   120   165   220 
    1  5 15  35  70  126  210   330   495   715 
    1  6 21  56 126  252  462   792  1287  2002 
    1  7 28  84 210  462  924  1716  3003  5005 
    1  8 36 120 330  792 1716  3432  6435 11440 
    1  9 45 165 495 1287 3003  6435 12870 24310 
    1 10 55 220 715 2002 5005 11440 24310 48620
    
     
    
    相信聰明的,你,一定,看出了DP方程。
    
    f[i][j]=f[i-1][j]+f[i][j-1];
    
    不要問我為什麼,DP是玄學。
    
    代碼實現(10):
    
    #include<cstdio>
    int n,m,f[3000][3000];
    int main(){
    scanf("%d%d",&n,&m);f[0][1]=1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    f[i][j]=f[i-1][j]+f[i][j-1];
    printf("%d
    ",f[n][m]);
    return 0;
    }
    
    為什麼還是10分,啊啊啊。。。(省略很多)
    
    我們來看看問題,
    
    Wa:爆int了。
    
    Re:開的數組不夠大了。
    
    對於Re,因為根據DP方程看,我們只需要一層的數據就夠了。(f[j]+=f[j-1];)
    
    對於Wa,我們只需要使用高精就行了。
    
    還有一個Tle,恩,可能是哪裡卡住了吧。
    
    恩,讓我平靜一下。
    
    代碼實現(不要管這個):我正寫著寫著,旁邊那個同學突然說,****,這個題是組合數,你看看題解,沒有用DP的。
    
    啊,我的上帝原諒我,我點擊題解,快速瀏覽了一下,好像真的,而且一個大佬還說最高二十萬位的樣子。
    
    。。。
    
    慫它嗎?
    
    舉(5,5)為例,按f[5][5]=f[4][5]+f[5][4];f[4][5]=f[3][5]+f[4][4],f[5][4]=f[4][4]+f[5][3];f[3][5]=f[2][5]+f[3][4],2*f[4][4]=2*f[4][3]+2*f[3][4];f[5][3]=f[5][2]+f[4][3]......
    
    即f[5][5]=20*f[2][1]+10*f[3][1]+4*f[4][1]+f[5][1]+20*f[1][2]+10*f[1][3]+4*f[1][4]+1*f[1][5]=20+10+4+1+20+10+4+1;
    
    額,你看出什麼來了嗎?我沒看出來。。。
    
    那麼,
    
    1   1   1    1     1       1       1        1           1         1
    1   2   3    4     5       6       7        8           9       10
    1   3   6   10   15     21     28      36        45       55
    1   4 10   20   35     56     84     120     165     220
    1   5 15   35   70   126   210     330     495     715
    1   6 21   56 126   252   462     792   1287   2002
    1   7 28   84 210   462   924   1716   3003   5005
    1   8 36 120 330   792 1716   3432   6435 11440
    1   9 45 165 495 1287 3003   6435 12870 24310 
    1 10 55 220 715 2002 5005 11440 24310 48620
    
    f[2][3]=f[2][1]+f[1][2]+f[1][3]=1+1+1;
    
    f[3][3]=f[3][1]+2*f[2][1]+2f[1][2]+f[1][3]=1+2+2+1;
    
    f[4][3]=f[4][1]+2*f[3][1]+3*f[2][1]+3*f[1][2]+f[1][3]=1+2+3+3+1;
    
    f[5][3]=......
    心路歷程

    好吧,C(n,m)=m!/n!(m-n)!。

    要處理一下n、m。

    if(n<m){a=m,m=n,n=a;}
    n--;m+=n-1;

    也就是組合數加高精。

    代碼實現:

     1 #include<cstdio>
     2 using namespace std;
     3 int n,m,a,ans[13000]={1,1},bz[13000];
     4 int s[40000],g[40000];
     5 int v[40000];
     6 void zzs(int x,bool y){
     7     for(int j=1;j<=s[0]&&x!=1;j++)
     8     while(x%s[j]==0){
     9         if(y) ++g[j];
    10         else --g[j];
    11         x/=s[j];
    12     }
    13 }
    14 void gjc(int x){
    15     g[x]--;
    16     for(int i=1;i<=ans[0];i++){
    17         ans[i]=ans[i]*s[x]+bz[i];bz[i]=0;
    18         if(ans[i]>9){
    19             bz[i+1]=ans[i]/10;
    20             ans[i]%=10;
    21             if(i==ans[0]) ++ans[0];
    22         }
    23     }
    24 }
    25 int main(){
    26     for(int i=2;i<=40000;i++)
    27     if(!v[i]){
    28         a=2*i;s[++s[0]]=i;
    29         while(a<=40000){v[a]=1;a+=i;}
    30     }
    31     scanf("%d%d",&n,&m);
    32     if(n<m){a=m,m=n,n=a;}
    33     n--;m+=n-1;
    34     for(int i=n+1;i<=m;i++) zzs(i,1);
    35     for(int i=1;i<=m-n;i++) zzs(i,0);
    36     for(int i=1;i<=s[0];i++)
    37     while(g[i]) gjc(i);
    38     for(int i=ans[0];i>0;i--) printf("%d",ans[i]);
    39     printf("
    ");
    40     return 0;
    41 }

    最高12039位,呵呵。

  • 相关阅读:
    Catharanthus roseus(长春花碱)的生物合成
    论文好句积累
    C# OpenFileDialog用法
    JAVA配置环境变量的意义
    如何为织梦表单添加时间
    winform开发基础
    tomcat中jsp编译
    垂直居中——父元素高度确定的单行文本、父元素高度确定的多行文本
    水平居中——行内元素、定宽块、不定宽块
    批处理文件
  • 原文地址:https://www.cnblogs.com/J-william/p/6046719.html
Copyright © 2020-2023  润新知