BZOJ 4945 NOI2017 游戏 搜索+2-SAT
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4945
分析:
首先考虑没有x的情况,发现有一个明显的推理模型,容易看出来可以用2-SAT做。
然后考虑有x的情况,发现最多只有8个x,不难想到可以搜索每个x为a,b,c中的哪个然后跑2-SAT。但是算算时间发现会T。
再仔细分析,发现只需要枚举两种情况就可以了。因为可行的对象已经全部在这两种情况里面包含了!
发现真的tarjan比另外一个算法快......事实证明另外一个算法(我叫不出名字ORZ)是可以被卡成O(NM)的。(从此入了tarjan的教。。。)
此题细节令人开心。
时间复杂度O((N+M)*2^x)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 const int maxn=50005; 14 const int maxm=100005; 15 16 int N,D,M; 17 char S[maxn]; 18 struct edge{ int to,next; }E[maxm<<1]; 19 struct data{ int i,j; char hi,hj; }da[maxm]; 20 int first[maxn<<1],_first[maxn<<1],np,pos[10],cnt,stk[maxn<<1],top; 21 int dfn[maxn<<1],sccno[maxn<<1],dfs_clock,scc_cnt,low[maxn<<1]; 22 bool bad[maxn<<1],_bad[maxn<<1]; 23 24 void _scanf(int &x) 25 { 26 x=0; 27 char ch=getchar(); 28 while(ch<'0'||ch>'9') ch=getchar(); 29 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 30 } 31 void _scanf(char &x) 32 { 33 x=getchar(); 34 while(!isalpha(x)) x=getchar(); 35 } 36 void add_edge(int u,int v,int *f) 37 { 38 E[++np]=(edge){v,f[u]}; 39 f[u]=np; 40 } 41 int id(int i,char a) 42 { 43 if(S[i]=='a') return i*2-(a=='B'?1:0); 44 return i*2-(a=='A'?1:0); 45 } 46 int _id(int i,bool k) 47 { 48 if(k) return S[i]=='a'?1:0; 49 return S[i]=='c'?1:2; 50 } 51 void data_in() 52 { 53 _scanf(N);_scanf(D);scanf("%s",S+1);_scanf(M); 54 int a,b; char hi,hj; 55 for(int i=1;i<=N;i++) 56 if(S[i]=='x') pos[++cnt]=i; 57 cnt=0; 58 for(int i=1;i<=M;i++){ 59 _scanf(a);_scanf(hi);_scanf(b);_scanf(hj); 60 if(S[a]-hi==32) continue; 61 if(S[a]=='x'||S[b]=='x'){ 62 da[++cnt]=(data){a,b,hi,hj}; 63 continue; 64 } 65 if(S[b]-hj==32){ bad[id(a,hi)]=1; continue; } 66 a=id(a,hi),b=id(b,hj); 67 add_edge(a,b,first); add_edge((b-1^1)+1,(a-1^1)+1,first); 68 } 69 } 70 void tarjan_scc(int i) 71 { 72 if(_bad[i]) return; 73 dfn[i]=low[i]=++dfs_clock; 74 stk[++top]=i; 75 for(int p=_first[i];p;p=E[p].next){ 76 int j=E[p].to; 77 if(dfn[j]){ 78 if(!sccno[j]) low[i]=min(low[i],dfn[j]); 79 continue; 80 } 81 tarjan_scc(j); 82 low[i]=min(low[i],low[j]); 83 } 84 if(low[i]==dfn[i]){ 85 scc_cnt++; 86 while(stk[top]!=i) sccno[stk[top--]]=scc_cnt; 87 sccno[stk[top--]]=scc_cnt; 88 } 89 } 90 bool judge() 91 { 92 memset(dfn,0,sizeof(dfn)); 93 memset(sccno,0,sizeof(sccno)); 94 memset(low,0,sizeof(low)); 95 dfs_clock=scc_cnt=top=0; 96 for(int i=1;i<=N*2;i++) 97 if(!dfn[i]) tarjan_scc(i); 98 for(int i=1;i<=N;i++) 99 if(sccno[i*2-1]==sccno[i*2]) return 0; 100 return 1; 101 } 102 bool run(int i) 103 { 104 if(i>D){ 105 memcpy(_first,first,sizeof(first)); 106 memcpy(_bad,bad,sizeof(bad)); 107 int tmp=np,a,b; 108 for(int k=1;k<=cnt;k++){ 109 if(S[da[k].i]-da[k].hi==32) continue; 110 if(S[da[k].j]-da[k].hj==32){ _bad[id(da[k].i,da[k].hi)]=1; continue; } 111 a=id(da[k].i,da[k].hi),b=id(da[k].j,da[k].hj); 112 add_edge(a,b,_first); add_edge((b-1^1)+1,(a-1^1)+1,_first); 113 } 114 np=tmp; 115 return judge(); 116 } 117 S[pos[i]]='a'; if(run(i+1)) return 1; 118 S[pos[i]]='b'; if(run(i+1)) return 1; 119 return 0; 120 } 121 void work() 122 { 123 if(!run(1)) printf("%d\n",-1); 124 else{ 125 for(int i=1;i<=N;i++){ 126 if(!sccno[i*2-1]) putchar('A'+_id(i,0)); 127 else if(!sccno[i*2]) putchar('A'+_id(i,1)); 128 else if(sccno[i*2]<sccno[i*2-1]) putchar('A'+_id(i,0)); 129 else putchar('A'+_id(i,1)); 130 } 131 putchar('\n'); 132 } 133 } 134 int main() 135 { 136 data_in(); 137 work(); 138 return 0; 139 }