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 }

 

你可能感兴趣的:(OS)