Vijos 1286 座位安排(状态压缩DP)

题目链接

先是一个转化,将n和m中较小的的为m这样状态数会小于1<<9。看题后,是嘛想法都啊没有。。看了DISUSS中有人提到这点。。。

写完,调了一下,尝试了几次,发现有两组过不了。想想极限数据,可能还是会爆__int64,然后乱搞改编一下,求组合数模版。。。水过了。。。

还是用STL中vector写的。。。以后还是用数组把。。。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <vector>
  5 using namespace std;
  6 #define LL unsigned __int64
  7 LL dp1[1<<9][21];
  8 LL dp2[1<<9][21];
  9 int o[1<<9];
 10 vector<int> ve;
 11 vector<int>::iterator it1,it2;
 12 LL gcd(LL a,LL b)
 13 {
 14     return b == 0 ? a:gcd(b,a%b);
 15 }
 16 LL c(int n,int m)
 17 {
 18     int i,j;
 19     if(n-m < m)
 20         m = n-m;
 21     LL s;
 22     for(i = 1,s = 1,j = 1;j <= m;n--,j ++)
 23     {
 24         s = s*n;
 25         while(s%i == 0&&i <= m)//这里防止爆精度
 26         {
 27             s = s/i;
 28             i ++;
 29         }
 30     }
 31     return s;
 32 }
 33 int main()
 34 {
 35     int n,m,k,i,j,t;
 36     LL ans;
 37     scanf("%d%d%d",&n,&m,&k);
 38     if(m > n)
 39     {
 40         t = m;
 41         m = n;
 42         n = t;
 43     }
 44     for(i = 0; i < 1<<m; i ++)
 45     {
 46         for(j = 0; j < m; j ++)
 47         {
 48             if(i&(1<<j))
 49                 o[i] ++;
 50         }
 51     }
 52     for(i = 0; i < 1<<m; i ++)
 53     {
 54         if(i&(i>>1)||i&(i<<1))
 55             ;
 56         else
 57         {
 58             if(o[i] <= k)
 59             {
 60                 dp1[i][o[i]] = 1;
 61                 ve.push_back(i);
 62             }
 63         }
 64     }
 65     for(i = 2; i <= n; i ++)
 66     {
 67         for(it1 = ve.begin(); it1 != ve.end(); it1 ++)
 68         {
 69             for(it2 = ve.begin(); it2 != ve.end(); it2 ++)
 70             {
 71                 for(j = 0; j <= k; j ++)
 72                 {
 73                     if((*it1)&(*it2))
 74                         ;
 75                     else
 76                     {
 77                         if(o[(*it2)]+j <= k)
 78                             dp2[(*it2)][o[(*it2)]+j] += dp1[(*it1)][j];
 79                     }
 80                 }
 81             }
 82         }
 83         for(it1 = ve.begin(); it1 != ve.end(); it1 ++)
 84         {
 85             for(j = 0; j <= k; j ++)
 86             {
 87                 dp1[(*it1)][j] = dp2[(*it1)][j];
 88                 dp2[(*it1)][j] = 0;
 89             }
 90         }
 91     }
 92     ans = 0;
 93     for(i = 0; i < 1<<m; i ++)
 94     {
 95         ans += dp1[i][k];
 96     }
 97     LL temp,comb;
 98     comb = c(m*n,k);
 99     temp = gcd(ans,comb);
100     if(ans != 0)
101         printf("%I64d/%I64d\n",comb/temp,ans/temp);
102     else
103         printf("Impossible!\n");
104     return 0;
105 }

 

posted @ 2013-03-13 19:51  Naix_x  阅读(308)  评论(0编辑  收藏  举报