Voting CodeForces - 749C
有点意思的题
题意:有n个人投票,每次按照第1个人~第n个人的顺序发言,如果到某个人发言时他已经被禁止发言就跳过,每个人发言时可以禁止另一个人发言或什么也不做。最后只剩下一个人时,那个人的意见就是最终决定的意见。这些人分为D和R两派,也就是每个人有D和R两种意见中的一种,每一派的人都希望自己派的意见成为最终意见。假设每个人都作出最优选择,请根据每个人的派别判断最终决定的意见。
方法:第i个人发言的时候,就按照第i~第n,第1~第i-1的顺序找出第一个出现的与自己不同派别且没有被禁言的人,将其禁言。当只剩下某一派时,显然这一派的意见就是最终意见。
方法虽然简单,但是实现起来会遇到很多困难。
垃圾程序(模拟)1
1 #include<cstdio> 2 int type[200100]; 3 int next1[200100];//next1[i]表示i之后第一个不同党的位置 4 int first1[2];//first1[i]表示从前数起第一个i的位置 5 int next2[200100];//next2[i]表示i之后第一个同党的位置 6 int temp[2]; 7 bool nok[200100]; 8 int n,now; 9 int main() 10 { 11 int i; 12 char c; 13 scanf("%d\n",&n); 14 for(i=1;i<=n;i++) 15 { 16 scanf("%c",&c); 17 if(c=='D') 18 type[i]=0; 19 else 20 type[i]=1; 21 } 22 for(i=n;i>=1;i--) 23 { 24 next1[i]=temp[type[i]^1]; 25 temp[type[i]]=i; 26 } 27 for(i=n;i>=1;i--) 28 { 29 next2[i]=first1[type[i]]; 30 first1[type[i]]=i; 31 } 32 now=n; 33 while(true) 34 { 35 for(i=1;i<=n;i++) 36 { 37 if(nok[i]) continue; 38 if(now==1) 39 { 40 if(type[i]==0) 41 printf("D"); 42 else 43 printf("R"); 44 return 0; 45 } 46 while(nok[next1[i]]==true) next1[i]=next2[next1[i]]; 47 while(nok[first1[i]]==true) first1[i]=next2[next1[i]]; 48 if(next1[i]) 49 { 50 nok[next1[i]]=true; 51 next1[i]=next2[next1[i]]; 52 } 53 else if(first1[type[i]^1]) 54 { 55 nok[first1[type[i]^1]]=true; 56 first1[type[i]^1]=next2[first1[type[i]^1]]; 57 } 58 else 59 { 60 if(type[i]==0) 61 printf("D"); 62 else 63 printf("R"); 64 return 0; 65 } 66 } 67 } 68 return 0; 69 }
垃圾程序(模拟)2
1 #include<cstdio> 2 int type[200100]; 3 int next1[200100];//next1[i]表示i之后第一个不同党的位置 4 int first1[2];//first1[i]表示从前数起第一个i的位置 5 int next2[200100];//next2[i]表示i之后第一个同党的位置 6 int temp[2]; 7 bool nok[200100]; 8 int n,now; 9 int main() 10 { 11 int i; 12 char c; 13 scanf("%d\n",&n); 14 for(i=1;i<=n;i++) 15 { 16 scanf("%c",&c); 17 if(c=='D') 18 type[i]=0; 19 else 20 type[i]=1; 21 } 22 for(i=n;i>=1;i--) 23 { 24 next1[i]=temp[type[i]^1]; 25 temp[type[i]]=i; 26 } 27 for(i=n;i>=1;i--) 28 { 29 next2[i]=first1[type[i]]; 30 first1[type[i]]=i; 31 } 32 now=n; 33 while(true) 34 { 35 for(i=1;i<=n;i++) 36 { 37 if(nok[i]) continue; 38 if(now==1) 39 { 40 if(type[i]==0) 41 printf("D"); 42 else 43 printf("R"); 44 return 0; 45 } 46 while(nok[next1[i]]==true) next1[i]=next2[next1[i]]; 47 while(nok[first1[i]]==true) first1[i]=next2[first1[i]]; 48 if(next1[i]) 49 { 50 nok[next1[i]]=true; 51 now--; 52 next1[i]=next2[next1[i]]; 53 } 54 else if(first1[type[i]^1]) 55 { 56 nok[first1[type[i]^1]]=true; 57 now--; 58 first1[type[i]^1]=next2[first1[type[i]^1]]; 59 } 60 else 61 { 62 if(type[i]==0) 63 printf("D"); 64 else 65 printf("R"); 66 return 0; 67 } 68 } 69 } 70 return 0; 71 }
后来看了题解,发现可以用三个队列按照(i~n,1~i-1)的顺序分别存储(所有的,与当前人同派的,与当前人异派的)且未被禁言的人的序号
然后,又炸了两次...所以要小心
1 //第i个人按照先i到n,再1到i-1的顺序找出第一个不同派别的deny 2 #include<cstdio> 3 #include<queue> 4 using namespace std; 5 bool type[200100]; 6 bool deny[200100]; 7 queue<int> q[2],q2; 8 int n; 9 int main() 10 { 11 int i,now,now2; 12 char c; 13 scanf("%d\n",&n); 14 for(i=1;i<=n;i++) 15 { 16 scanf("%c",&c); 17 if(c=='R') 18 type[i]=1; 19 q[type[i]].push(i); 20 q2.push(i); 21 } 22 while(!q[0].empty()&&!q[1].empty()) 23 { 24 now=q2.front(); 25 q2.pop(); 26 if(deny[now]) continue; 27 //此时now就为当前要发言的(未被禁言的)人 28 now2=q[type[now]^1].front();//now要禁言的人 29 q[type[now]^1].pop();//由于now2被禁言,就不放回队列了 30 deny[now2]=true; 31 q[type[now]].pop();//第二次交加上的,now已经发完言,从队列中退出 32 q[type[now]].push(now);//第三次交加上的,并放回到队列尾部 33 q2.push(now); 34 } 35 if(q[0].empty()) 36 printf("R"); 37 else 38 printf("D"); 39 return 0; 40 }