Description
有A~Z这26张牌,现在从中抽出三张并把剩余23张分给选手1和2,现在有n次查询,每次询问一个选手是否有某两张牌,和选手的回答,回答是说自己有这两张牌中的几张,问拿出的三张牌有多少种方案能够满足这n个条件
Input
第一行一整数n表示查询数,每组查询输入两个字符表示要查询的两张牌,以及要查询的选手编号(1or2),以及选手的回答(0,1,2)表示这两张牌手里有多少张(0<=n<=50)
Output
输出合法方案数
Sample Input
3
AB 1 1
AC 2 1
BC 2 1
Sample Output
506
Solution
首先处理0张和2张的情况,遇见不合法情况直接gg,那么剩下的就是1张的情况,枚举拿出的三张牌用并查集判是否合法,i表示1选手拿第i张牌,i+26表示2选手拿第i张牌,0表示一定拿,53表示一定拿,对于拿出的三张牌x,y,z,如果某位选手拿了则不合法,没有则两位选手都不拿这三张牌,之后处理1张查询中涉及到x,y,z这三张牌的查询,设这次查询问的是a,b,如果a,b都属于这三张牌则gg;如果没有属于这三种牌的则把1拿a和2拿b合并,2拿a和1拿b合并;如果a,b有一张属于这三张牌,那么该选手一定拿另一张牌,不妨另一张牌是b,那么就是当前选手一定拿b另一选手一定不拿b,这样就处理完1张的查询,然后处理除x,y,z之外某些被确定拿或不拿的牌,如果i牌两个人都一定不拿或一定拿则gg,如果一张牌1一定拿2一定不拿,则把i和0合并,i+26和53合并,如果1一定不拿2一定拿,则把i和53合并,i+26和0合并,所有合并操作结束,判断fa[i]和fa[i+26]是否相同,如果相同说明两位选手拿了同一张牌,不合法;然后判断fa[0]和fa[53]是否相同,如果相同说明一位选手拿某张牌又不拿某张牌才会把0和53合并,不合法;否则合法
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<string>
using namespace std;
#define maxn 55
int fa[maxn];
void init(int n)
{
for(int i=0;i<=n;i++)fa[i]=i;
}
int find(int x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y)return ;
fa[x]=y;
}
int n,q[55][3],res,vis[2][33],mark[2][33],used[55];
char op[5];
bool check(int x,int y,int z)
{
init(53);
for(int i=0;i<2;i++)
for(int j=1;j<=26;j++)
mark[i][j]=vis[i][j];
for(int i=0;i<2;i++)
{
if(mark[i][x]==1||mark[i][y]==1||mark[i][z]==1)return 0;
mark[i][x]=mark[i][y]=mark[i][z]=-1;
}
for(int i=1;i<=res;i++)
{
int f1=0,f2=0,a=q[i][0],b=q[i][1],c=q[i][2];
if(b==x||b==y||b==z)f1=1;
if(c==x||c==y||c==z)f2=1;
if(f1&&f2)return 0;
if(f2)swap(b,c),swap(f1,f2);
if(f1)
{
int t1=a*26+c,t2=(a^1)*26+c;
unite(t1,0),unite(t2,53);
}
else
{
int t1=a*26+b,t2=a*26+c,t3=(a^1)*26+b,t4=(a^1)*26+c;
unite(t1,t4),unite(t2,t3);
}
}
for(int i=1;i<=26;i++)
if(i!=x&&i!=y&&i!=z)
{
if(mark[0][i]==1&&mark[1][i]==1)return 0;
if(mark[0][i]==-1&&mark[1][i]==-1)return 0;
if(mark[0][i]==1||mark[1][i]==-1)unite(i,0),unite(26+i,53);
else if(mark[1][i]==1||mark[0][i]==-1)unite(i,53),unite(26+i,0);
}
if(fa[0]==fa[53])return 0;
for(int i=1;i<=26;i++)
if(fa[i]==fa[i+26])return 0;
return 1;
}
int main()
{
while(~scanf("%d",&n))
{
res=0;
memset(vis,0,sizeof(vis));
int gg=0;
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%s%d%d",op,&a,&b);
a--;
int c=op[0]-'A'+1,d=op[1]-'A'+1;
if(c>d)swap(c,d);
if(b==0)
{
if(vis[a][c]==1||vis[a][d]==1)gg=1;
else vis[a][c]=vis[a][d]=-1;
}
else if(b==2)
{
if(vis[a][c]==-1||vis[a][d]==-1)gg=1;
else vis[a][c]=vis[a][d]=1;
}
else q[++res][0]=a,q[res][1]=c,q[res][2]=d;
}
int ans=0;
if(!gg)
{
for(int i=1;i<=26;i++)
for(int j=i+1;j<=26;j++)
for(int k=j+1;k<=26;k++)
if(check(i,j,k))ans++;
}
printf("%d\n",ans);
}
return 0;
}