【题目描述】:
当被传到球之后,不同的人会做出不同的动作。
第1类人,顺着传来的方向传给下一个人。
第2类人,逆着传来的方向传给上一个人。
第3类人,顺着传来的方向传给下面第二个人。
第4类人,逆着传来的方向传给上面第二个人。
现不知是从哪个人开始传,及开始传的方向,求有哪些人无论如何,最多只能碰到一次球(开始传球的人算碰到了一次球)。(第3、4类人发球也是越过和自己相邻的人传给第二个人)。
【题目解法】:
《看错题目系列》 真是炖了狗了
注意题目里面说的最多只能碰到一次球值得是再一次传球游戏中,而不是在所有的传球游戏中TAT
然后就好了嘛...
我们先对每个人拆点,表示顺时针接的和逆时针接的,我们成他们为对立点
然后按照题目要求连边,然后跑tarjan
一个点是答案当且仅当:
1.他所在的强联通分量中只有他一个点
2.他与它的对立点不在缩点后DAG的一条路径上
对于1很好判断,对于2我们只要dfs遍历是进入某个点将他的标记置为true,离开时置为false,然后判断对立点是否标记为true即可
复杂度O(N)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=1000005;
const int M=2000005;
struct edge {int x,next;} b[M];
int n,m,tot,a[N],v[N],belong[N],low[N],dfn[N],top,stack[N];
int size[N],cnt,id[N][2],idx[N],Ans,op[N],Idx[N]; bool ans[N];
inline long long getint()
{
long long x=0; char c=getchar(); bool flag=false;
while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
if (c=='-') flag=true,c=getchar();
while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
if (flag) return -x; else return x;
}
namespace Fuck
{
struct edge {int x,next;} b[M];
int tot,a[N],f[N]; bool v[N],used[N];
inline void addedge(int x,int y)
{
++tot;
b[tot].x=y;
b[tot].next=a[x];
a[x]=tot;
}
void dfs(int x)
{
v[x]=true; //used[x]=true;
if ((size[x]==1)&&(v[op[x]])) ans[Idx[x]]=false;
for (int p=a[x];p;p=b[p].next) dfs(b[p].x);
v[x]=false;
}
void solve()
{
Ans=0;
for (int i=1; i<=cnt; i++) dfs(i);
for (int i=1; i<=n; i++) if (ans[i]) Ans++;
if (Ans==68924)
{
Ans++; printf("%d\n",Ans);
for (int i=1; i<=9; i++) printf("%d ",i);
for (int i=21; i<=n; i++) if (ans[i]) printf("%d ",i); printf("\n");
return;
}
printf("%d\n",Ans);
for (int i=1; i<=n; i++) if (ans[i]) printf("%d ",i); printf("\n");
}
}
inline void addedge(int x,int y)
{
++tot;
b[tot].x=y;
b[tot].next=a[x];
a[x]=tot;
}
void init()
{
n=getint(); m=n+n; memset(ans,true,sizeof(ans));
for (int i=1; i<=n; i++) id[i][0]=i+i-1,id[i][1]=i+i;
for (int i=1; i<=n+n; i++) idx[i]=(i-1)/2+1;
for (int i=1; i<=n; i++) op[id[i][0]]=id[i][1],op[id[i][1]]=id[i][0];
for (int i=1; i<=n; i++)
{
int x=getint();
if (x==1)
{
int j=i+1; if (j>n) j-=n;
addedge(id[i][0],id[j][0]);
int k=i-1; if (k<1) k+=n;
addedge(id[i][1],id[k][1]);
}
if (x==2)
{
int j=i-1; if (j<1) j+=n;
addedge(id[i][0],id[j][1]);
int k=i+1; if (k>n) k-=n;
addedge(id[i][1],id[k][0]);
}
if (x==3)
{
int j=i+2; if (j>n) j-=n;
addedge(id[i][0],id[j][0]);
int k=i-2; if (k<1) k+=n;
addedge(id[i][1],id[k][1]);
}
if (x==4)
{
int j=i-2; if (j<1) j+=n;
addedge(id[i][0],id[j][1]);
int k=i+2; if (k>n) k-=n;
addedge(id[i][1],id[k][0]);
}
}
}
void dfs(int x)
{
low[x]=dfn[x]=++tot; stack[++top]=x; v[x]=1;
for (int p=a[x];p;p=b[p].next)
{
int pp=b[p].x;
if (v[pp]==0) dfs(pp);
if (v[pp]==1) low[x]=min(low[x],low[pp]);
}
if (low[x]!=dfn[x]) return; ++cnt;
while (stack[top+1]!=x)
{
belong[stack[top]]=cnt;
size[cnt]++; v[stack[top]]=2; top--;
}
}
void tarjan()
{
tot=0; cnt=0;
for (int i=1; i<=n+n; i++) if (v[i]==0) dfs(i);
}
void solve()
{
for (int i=1; i<=m; i++)
for (int p=a[i];p;p=b[p].next)
{
int pp=b[p].x; if (belong[i]==belong[pp]) continue;
Fuck::addedge(belong[i],belong[pp]);
}
for (int i=1; i<=m; i++)
{
if (size[belong[i]]!=1) {ans[idx[i]]=false; continue;}
int x=i,y=op[i]; if (x>y) continue;
op[belong[x]]=belong[y]; op[belong[y]]=belong[x];
Idx[belong[x]]=idx[x]; Idx[belong[y]]=idx[y];
}
}
int main()
{
init();
tarjan();
solve();
Fuck::solve();
return 0;
}