• 【BZOJ】【3907】网格


    组合数学/python


    3907: 网格

    Time Limit: 1 Sec  Memory Limit: 256 MB
    Submit: 162  Solved: 76
    [Submit][Status][Discuss]

    Description

    某 城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m。现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的点,即任何途径的点(x, y)都要满足x >= y,请问在这些前提下,到达B(n, m)有多少种走法。

    Input

    输入文件中仅有一行,包含两个整数n和m,表示城市街区的规模。

    Output

    输出文件中仅有一个整数和一个换行/回车符,表示不同的方案总数。

    Sample Input

    6 6

    Sample Output

    132

    HINT

    100%的数据中,1 <= m <= n <= 5 000


    Source

    [Submit][Status][Discuss]

      题面很容易想到Catalan数……但是5000的范围实在是有些吃不消……

      题解:http://www.cnblogs.com/mhy12345/p/4343980.html

    copy了下代码sorry……  

      UPD:(2015-04-02 16:53:03)

      好吧我还是来写一下吧:

        我们求不越过$y=x$这条线的方案数不是很好求,那么我们就利用补集转化的思想来求。首先所有方案的总数是$C(n+m,n)$,其中所有不合法的方案,即中途跨过了$ y=x $这条线的路径,我们都可以将跨越点之后的路径翻折一下,得到一条从(1,1)到(m,n)的路线,也就是说,所有不合法的方案数之和即为C(n+m,n-1)。容我三思QAQ,或者哪位路过的神犇指点我一下……

        啊哩怎么跟我当初抄的代码不太一样= =?

     1 /**************************************************************
     2     Problem: 3907
     3     User: Tunix
     4     Language: Python
     5     Result: Accepted
     6     Time:1184 ms
     7     Memory:79228 kb
     8 ****************************************************************/
     9 
    10 def C(n,m):
    11     return fact[n]/fact[m]/fact[n-m];
    12 f=raw_input().split(" ");
    13 n=int(f[0]);
    14 m=int(f[1]);
    15 tot=max(n,m)*2;
    16 fact=[1];
    17 for i in range(1,tot+1):
    18     fact.append(fact[-1]*i);
    19 c=n-m;
    20 ans=C(tot-c,tot/2)-C(tot-c,tot/2+1);
    21 print ans;
    View Code

       UPD:(2015年4月19日 20:21:03)

      Orz ykz神犇,提供了他的题解&高精C++代码:

    我们假设0表示向右走,1表示向上走,那么很显然问题可以转化为:给你n个0和m个1,求出满足某个条件的01串的个数,这个条件是——对于任意一个子串s[1…i],0的个数不小于1的个数。我们可以用补集转化的方法,所有的01串的个数为$inom{n+m}{m}$,然后我们再考虑不合法的01串个数。我们假定现在有一个01串,它的0和1的个数分别是n和m,第一次出现不满足条件的位置是i。即s[1…i]当中,0的个数=1的个数-1,并且s[i]=1。我们把s[1…i]的所有0变成1,1变成0,这样,我们得到的新的01串,这个串当中,0和1的个数分别为n+1,m-1。我们发现,这个转化是一一对应的,也就是说,每一个不合法的01串,都对应了一个唯一的一个n+1,m-1的01串;而这个n+1,m-1的01串也正好和唯一的这个不合法串对应,满足充要性。于是我们得到了不合法的01串的个数就是$inom{n+m}{m-1}$。然后就可以出解啦,为了避免除以0(因为有m-1)我们这么搞:$$ans=inom{n+m}{m}-inom{n+m}{n+1} ( inom{n+m}{m-1}=inom{n+m}{n+1})$$
     1 /**************************************************************
     2     Problem: 3907
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:84 ms
     7     Memory:944 kb
     8 ****************************************************************/
     9  
    10 #include<cstdio>
    11 #include<cstring>
    12  
    13 typedef long long LL;
    14  
    15 const int N=10001;
    16 const LL mod=100000000;
    17  
    18 int tot=0,x[N],p[N],v[N]={0};
    19 LL a[1000],b[1000];
    20  
    21 LL pow(LL x,int p) {
    22     LL t=1;for (;p;p>>=1,x*=x) if (p&1) t*=x;return t;
    23 }
    24  
    25 void mul(LL a[],LL y) {
    26     LL x=0,&l=a[0];
    27     for (int i=1;i<=l;i++) {
    28         a[i]=a[i]*y+x;
    29         x=a[i]/mod;
    30         a[i]%=mod;
    31     }
    32     while (x) a[++l]=x%mod,x/=mod;
    33 }
    34  
    35 void dec(LL a[],LL b[]) {
    36     LL &l=a[0];
    37     for (int i=1;i<=l;i++) {
    38         if (a[i]<b[i]) a[i+1]--,a[i]+=mod;
    39         a[i]-=b[i];
    40     }
    41     while (!a[l]) l--;
    42 }
    43  
    44 void getc(LL a[],int n,int m) {
    45     memset(x,0,sizeof x);
    46     for (int i=2;i<=n;i++) x[i]++;
    47     for (int i=2;i<=m;i++) x[i]--;
    48     for (int i=2;i<=n-m;i++) x[i]--;
    49     for (int i=n;i>=2;i--)
    50     if (!v[i]) mul(a,pow(i,x[i]));
    51     else x[v[i]]+=x[i],x[i/v[i]]+=x[i];
    52 }
    53  
    54 void print(LL a[]) {
    55     int l=a[0];
    56     printf("%lld",a[l]);
    57     for (int i=l-1;i>=1;i--) printf("%08lld",a[i]);
    58     printf("
    ");
    59 }
    60  
    61 int main() {
    62     int n,m;
    63     scanf("%d%d",&n,&m);
    64     for (int i=2;i<=n+m;i++) {
    65         if (!v[i]) p[++tot]=i;
    66         for (int j=1,k;j<=tot,(k=p[j]*i)<=n+m;j++) {
    67             v[k]=p[j];
    68             if (i%p[j]==0) break;
    69         }
    70     }
    71     a[0]=a[1]=b[0]=b[1]=1;
    72     getc(a,n+m,n);
    73     getc(b,n+m,n+1);
    74     dec(a,b);
    75     print(a);
    76     return 0;
    77 }
    78 
    View Code
  • 相关阅读:
    emWin 界面切换注意事项
    emWin 工程之汉字显示
    emWin 使用 GUIBuilder 放置标题 TEXT 注意
    【转】系统调用和驱动程序中相应函数的参数对应关系
    主机 & 虚拟机 & 开发板 相互通信
    电脑通过网口连接开发板
    【转】ARM交叉编译工具链
    【转】vi 写完文件保存时才发现是 readonly
    【转】ubuntu 12.04下如何开启 NFS 服务 & 设置
    安装完打开 eclipse 提示 JVM 版本较低
  • 原文地址:https://www.cnblogs.com/Tunix/p/4354348.html
Copyright © 2020-2023  润新知