您的位置:首页 > 其它

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

2013-03-13 19:51 381 查看
题目链接

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

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

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

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
#define LL unsigned __int64
LL dp1[1<<9][21];
LL dp2[1<<9][21];
int o[1<<9];
vector<int> ve;
vector<int>::iterator it1,it2;
LL gcd(LL a,LL b)
{
return b == 0 ? a:gcd(b,a%b);
}
LL c(int n,int m)
{
int i,j;
if(n-m < m)
m = n-m;
LL s;
for(i = 1,s = 1,j = 1;j <= m;n--,j ++)
{
s = s*n;
while(s%i == 0&&i <= m)//这里防止爆精度
{
s = s/i;
i ++;
}
}
return s;
}
int main()
{
int n,m,k,i,j,t;
LL ans;
scanf("%d%d%d",&n,&m,&k);
if(m > n)
{
t = m;
m = n;
n = t;
}
for(i = 0; i < 1<<m; i ++)
{
for(j = 0; j < m; j ++)
{
if(i&(1<<j))
o[i] ++;
}
}
for(i = 0; i < 1<<m; i ++)
{
if(i&(i>>1)||i&(i<<1))
;
else
{
if(o[i] <= k)
{
dp1[i][o[i]] = 1;
ve.push_back(i);
}
}
}
for(i = 2; i <= n; i ++)
{
for(it1 = ve.begin(); it1 != ve.end(); it1 ++)
{
for(it2 = ve.begin(); it2 != ve.end(); it2 ++)
{
for(j = 0; j <= k; j ++)
{
if((*it1)&(*it2))
;
else
{
if(o[(*it2)]+j <= k)
dp2[(*it2)][o[(*it2)]+j] += dp1[(*it1)][j];
}
}
}
}
for(it1 = ve.begin(); it1 != ve.end(); it1 ++)
{
for(j = 0; j <= k; j ++)
{
dp1[(*it1)][j] = dp2[(*it1)][j];
dp2[(*it1)][j] = 0;
}
}
}
ans = 0;
for(i = 0; i < 1<<m; i ++)
{
ans += dp1[i][k];
}
LL temp,comb;
comb = c(m*n,k);
temp = gcd(ans,comb);
if(ans != 0)
printf("%I64d/%I64d\n",comb/temp,ans/temp);
else
printf("Impossible!\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: