题目概述
有
A,B,C
三种车和
n
场比赛,每场比赛有一个限制
解题报告
ps:考网上同步赛的时候我只想到了没有
′x′
的做法,太弱了Orz
如果没有
′x′
,由于每场比赛已经限制了一种车,所以所有比赛都只能在两种车之间做选择,这是典型的2-SAT。但有了
′x′
,怎么办呢?
首先我们会想到DFS枚举所有
′x′
必定不选的车,然后就把
′x′
转化为普通的比赛了,接下来用2-SAT判断是否有解即可。但这样复杂度为
O(38∗(n+m))
,承受不了。
继续分析,我们会发现没必要枚举把
′a′,′b′,′c′
全部枚举过去:
′a′
代表的状态是第
B,C
种车,
′b′
代表的状态是第
A,C
种车,
′c′
代表的状态是第
A,B
种车。所以我们只需要随意选取两个枚举就可以覆盖到所有状况!
那么复杂度降为
O(28∗(n+m))
。
示例程序
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=50000,maxm=100000;
int n,D,m,ID[maxn+5],num[maxn+5][3],ans[maxn+5];;
int E,fst,lnk[2*maxn+5],nxt[2*maxm+5],son[2*maxm+5];
int ti,dfn[2*maxn+5],low[2*maxn+5],top,stk[2*maxn+5],tot,SCC[2*maxn+5];
bool instk[2*maxn+5];
struct data {int x,IDx,y,IDy;}a[maxm+5];
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
x=tot*f;
return Eoln(ch);
}
char getrch() {char ch=readc();while (('z'<ch||ch<'a')&&('Z'<ch||ch<'A')) ch=readc();return ch;}
void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];lnk[x]=E;}
void Tarjan(int x)
{
dfn[x]=low[x]=++ti;instk[x]=true;stk[++top]=x;
for (int j=lnk[x];j;j=nxt[j])
if (!dfn[son[j]]) Tarjan(son[j]),low[x]=min(low[x],low[son[j]]); else
if (instk[son[j]]) low[x]=min(low[x],dfn[son[j]]);
if (dfn[x]==low[x])
{
tot++;int y;
do y=stk[top--],SCC[y]=tot,instk[y]=false; while(y!=x);
}
}
bool Two_SAT()
{
E=0;memset(lnk,0,sizeof(lnk));
for (int i=1;i<=m;i++)
{
int x=a[i].x,y=a[i].y,IDx=a[i].IDx,IDy=a[i].IDy;
if (IDx==ID[x]) continue;
if (IDy==ID[y]) Add(num[x][IDx],num[x][IDx]^1);
Add(num[x][IDx],num[y][IDy]);
Add(num[y][IDy]^1,num[x][IDx]^1);
}
memset(dfn,0,sizeof(dfn));tot=0;
for (int i=0;i<2*n;i++) if (!dfn[i]) Tarjan(i);
for (int i=0;i<2*n;i+=2)
if (SCC[i]==SCC[i^1]) return false; else
if (SCC[i]<SCC[i^1]) ans[i/2]=i; else ans[i/2]=i^1;
return true;
}
bool Dfs(int st=0)
{
if (st==n) return Two_SAT();
if (ID[st]<3) return Dfs(st+1);
num[st][ID[st]=0]=-1;num[st][1]=st<<1;num[st][2]=st<<1^1;
bool fl=Dfs(st+1);if (fl) return true;
num[st][ID[st]=1]=-1;num[st][0]=st<<1;num[st][2]=st<<1^1;
fl=Dfs(st+1);ID[st]=3;return fl;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);readi(D);
for (int i=0;i<n;i++) switch (getrch())
{
case 'a':num[i][ID[i]=0]=-1;num[i][1]=i<<1;num[i][2]=i<<1^1;break;
case 'b':num[i][ID[i]=1]=-1;num[i][0]=i<<1;num[i][2]=i<<1^1;break;
case 'c':num[i][ID[i]=2]=-1;num[i][0]=i<<1;num[i][1]=i<<1^1;break;
case 'x':ID[i]=3;break;
}
readi(m);
for (int i=1;i<=m;i++)
{
readi(a[i].x);a[i].x--;a[i].IDx=getrch()-'A';
readi(a[i].y);a[i].y--;a[i].IDy=getrch()-'A';
}
if (!Dfs()) return printf("-1\n"),0;
for (int i=0;i<n;i++)
for (int j=0;j<3;j++)
if (ans[i]==num[i][j]) putchar(j+'A');
return 0;
}