逃离计划
【题目背景】
逃亡主义,全民公决。
【题目描述】
有 n 名议员,m 个逃离方案。每一个逃离方案都有可能通过或者不通过。可以有多个
方案同时通过。对于 m 个逃离方案的通过与否序列,称其为总方案 S。(即 m 个元素的
01 序列 0 表示不通过,1 表示通过)
第 i 名议员手中有 a[i]张选票,他会对 a[i]个方案进行投票,态度为通过或者不通过。
你需要根据所有的选票计算出总方案。并且要求每一个议员的选票中有超过一半的选票与
最后的总方案的态度相符。你同时还应当计算出哪一些方案的通过与否是确定的(即这个
方案在所有可能的总方案中的态度是一样的)。
【输入】(vote.in)
第一行有两个用一个空格分开的数你 n,m,意义同上。
接下来的 n*3 行,每 3 行描述了一个人的投票方案
1. a[i]意义同上
2. a[i]个正整数 表示这个人投票的方案
3. a[i]个整数只取 0 或 1 表示对上一行描述的 a[i]个方案的态度。0 表示不通过,
1 表示通过。态度与方案从左到右一一对应。
【输出】(vote.out)
如果不存在一个满足条件的总方案,输出’NO’(单引号不输出)否则
第一行为一个整数 S 表示总方案中有 S 个逃离方案的态度是确定的。接下来的 S 行,
每一行表示一个确定的逃离方案的标号(升序)。
【样例输入】
2 4
4
1 2 3 4
0 0 0 0
4
1 2 3 4
1 0 0 0
【样例输出】
3
2
3
4
【数据规模】
30%的数据 n,m<=200;
50%的数据 n,m<=2500
100%的数据 n<=10000 m<=20000 1<=a[i]<=4
【样例解释】
两种可行的方案:
0 0 0 0
1 0 0 0
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <vector>
using namespace std;
const int N=100010,M=200010;
struct Edge{
int cnt,fir[M*2],from[M*8];
int nxt[M*8],to[M*8];
void addedge(int a,int b){
nxt[++cnt]=fir[a];
to[fir[a]=cnt]=b;
from[cnt]=a;
}
}e,g;
int tim,vis[M*2],low[M*2];
int scnt,st[M*2],scc[M*2],top;
int n,m,a[N],b[N],id[N][2],idx;
void Tarjan(int x){
vis[x]=low[x]=++tim;st[++top]=x;
for(int i=e.fir[x];i;i=e.nxt[i])
if(!vis[e.to[i]]){
Tarjan(e.to[i]);
low[x]=min(low[x],low[e.to[i]]);
}
else if(!scc[e.to[i]])
low[x]=min(low[x],vis[e.to[i]]);
if(low[x]==vis[x]){
++scnt;
while(true){
int y=st[top--];
scc[y]=scnt;
if(x==y)break;
}
}
}
bool Check(){
for(int i=1;i<=idx;i++)
if(!vis[i])Tarjan(i);
for(int i=1;i<=m;i++)
if(scc[id[i][0]]==scc[id[i][1]])
return false;
return true;
}
int ans[M*2],calc;
int in[M*2],rk[M*2],ord[M*2];
int main(){
freopen("vote.in","r",stdin);
freopen("vote.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
id[i][0]=++idx;
id[i][1]=++idx;
}
for(int i=1,k;i<=n;i++){
scanf("%d",&k);
for(int j=1;j<=k;j++)
scanf("%d",&a[j]);
for(int j=1;j<=k;j++)
scanf("%d",&b[j]);
if(k<=2){
for(int j=1;j<=k;j++)
e.addedge(id[a[j]][b[j]^1],id[a[j]][b[j]]);
}
else{
for(int t1=1;t1<=k;t1++)
for(int t2=1;t2<=k;t2++)
if(t1!=t2)e.addedge(id[a[t1]][b[t1]^1],id[a[t2]][b[t2]]);
}
}
if(!Check()){
puts("NO");
return 0;
}
for(int i=1;i<=e.cnt;i++){
int x=scc[e.from[i]],y=scc[e.to[i]];
if(x!=y){g.addedge(x,y);in[y]+=1;}
}
top=tim=0;
for(int i=1;i<=scnt;i++)
if(!in[i])st[++top]=i;
while(top){
int x=st[top--];rk[x]=++tim;ord[tim]=x;
for(int i=g.fir[x];i;i=g.nxt[i])
if(--in[g.to[i]]==0)
st[++top]=g.to[i];
}
for(int t=1;t<=m;t++){
int S=scc[id[t][0]],T=scc[id[t][1]];
if(rk[S]>rk[T])swap(S,T);
st[top=1]=S;int flag=0;
for(int i=rk[S];i<=rk[T];i++)
vis[ord[i]]=0;
while(top){
int x=st[top--];vis[x]=true;
for(int i=g.fir[x];i;i=g.nxt[i])
if(rk[g.to[i]]<=rk[T]){
if(g.to[i]==T){flag=1;break;}
if(!vis[g.to[i]])st[++top]=g.to[i];
}
}
if(flag)ans[++calc]=t;
}
printf("%d\n",calc);
for(int i=1;i<=calc;i++)
printf("%d\n",ans[i]);
return 0;
}