传送门:http://poj.org/problem?id=3139
题目大意:给出16个不大于1024数,每个数只使用一次,求使得下列等式成立的方案数。
x1 * 4 + x2 * 3 + x3 * 2 + x4 = x5 + x6 * 2 + x7 * 3 + x8 * 4
y1 * 4 + y2 * 3 + y3 * 2 + y4 = y5 + y6 * 2 + y7 * 3 + y8 * 4
思路:G[x]记录的是能够组成和为x的四个数的集合(压缩成一个数表示),枚举四个数的全排列,算出tmp=bit[1]+bit[2]*2+bit[3]*3+bit[3]*4,然后找之前已经求过的也能凑成tmp的四个数的组合,若两者没有重复元素,则可以组成一组无重复的8个数的等式,这里问题就解决了一半了,这时候就可以把能够使等式满足的8个数的每种组合的方案数都求出来,放在state[x]里面保存,最后枚举一遍(0,1<<16),把无重复的两组8个数的组合的方案数相乘后(state[i]*state[((1<<16)-1)^i])累加到ans,由于枚举时候正反会重复,所以最后ans/2就是总共16个数使等式成立的方案数。
感想:位运算和状态压缩可以简化枚举的策略,也有许多意想不到的方便。
Code:
/* W w w mm mm 222222222 7777777777777 */
/* W w w w m m m m 222 22 7777 */
/* w w w w m m m m 22 777 */
/* w w w w m m m m 22 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* ww ww m mm m 222222222222222 77 */
//#pragma comment(linker, "/STACK:102400000,102400000")
//C++
//int size = 256 << 20; // 256MB
//char *p = (char*)malloc(size) + size;
//__asm__("movl %0, %%esp\n" :: "r"(p));
//G++
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<ctime>
#include<deque>
#include<cmath>
#include<vector>
#include<string>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#define REP(i,s,t) for(int i=(s);i<=(t);i++)
#define REP2(i,t,s) for(int i=(t);i>=s;i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned long ul;
const int N=20;
const int Maxans=10240+10;
int a[N];
int bit[N];
vector<int>G[Maxans];
int state[1<<17];
bool judge(int x)
{
int cnt=0;
REP(i,1,16)
{
if(x&(1<<(i-1)))
{
bit[++cnt]=a[i];
}
}
return cnt==4;
}
int fuck()
{
REP(i,0,Maxans)
{
G[i].clear();
}
memset(state,0,sizeof(state));
sort(a+1,a+1+16);
REP(i,0,(1<<16)-1)
{
if(judge(i))
{
do
{
int tmp=bit[1]*1+bit[2]*2+bit[3]*3+bit[4]*4;
for(int j=0;j<G[tmp].size();j++)
{
if((i&G[tmp][j])==0)
{
state[i|G[tmp][j]]++;
}
}
G[tmp].push_back(i);
}while(next_permutation(bit+1,bit+1+4));
}
}
int ans=0;
REP(i,0,(1<<16)-1)
{
ans+=state[i]*state[((1<<16)-1)^i];
}
return ans/2;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("test.in","r",stdin);
#endif
int ca=1;
while(~scanf("%d",&a[1]))
{
if(!a[1])
{
break;
}
REP(i,2,16)
{
scanf("%d",&a[i]);
}
int ans=fuck();
printf("Case %d: %d\n",ca++,ans);
}
return 0;
}