Voting-一道題來看set效率和queue效率
阿新 • • 發佈:2018-12-24
分析:策略是採取先deny第一個後於自己位置的對手,如果自己後面沒對手了就投剩下的對手中位置最靠前的,道理顯而易見,位置越前越有可能deny自己陣容的人,肯定要先“讓他說不了話”比較合理
一開始直接陣列模擬,while(1)遍歷陣列居然還能過前20多組資料,但這樣效率奇低,後來想用優先佇列(最小堆),每次把對面的根節點deny,但這樣不能保證是最優,例如樣test21的資料
7
RDRDDRD
這樣寫WA,原因是第三個D選擇deny的是第一個R而不是緊跟他的下一個R ,這顯然坑隊友,第四個D會被第三個R搞死(deny),
//WA 21 的版本
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 200005;
char s[maxn];
priority_queue<int,vector<int>,greater<int> > d,r;
int a[maxn]={0},b[maxn]={0};
int main()
{
int n;
scanf("%d",&n);
scanf("%s",s);
int i=0;
for(i=0;i<n;++i){
if (s[i]=='D'){
d.push(i);
a[i]=1;
}
else {
r.push(i);
b[i]=1;
}
}
i = -1;
while(1){
if(++i>n)i=0;
if(d.size()==0){
puts("R");
return 0;
}
if(r.size()==0){
puts ("D");
return 0;
}
if(a[i]){//D
b[r.top()]=0;
//printf("%d\n",r.top());
r.pop();
}
else if(b[i]){//R
a[d.top()]=0;;
//printf("%d\n",d.top());
d.pop();
}
}
return 0;
}
考慮到佇列沒查詢二分搜尋之類的,我糊里糊塗地用set做了,以為二分搜尋,查詢和刪除的複雜度是O(logN)時間會過,於是寫了下面這個版本
,仔細想一下其實肯定TLE啦,整個複雜度幾乎是O(n! *logN)
//TLE 12版本
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
const int maxn = 200050;
char s[maxn];
int d[maxn]={0},r[maxn]={0};
set<int> de,re;
int main()
{
int n;
scanf("%d",&n);
scanf("%s",s+1);
int i = 0;
for(i=1;i<=n;++i){
if(s[i]=='D'){
d[i]=1;
de.insert(i);
}else{
r[i]=1;
re.insert(i);
}
}
i = 0;
set<int>::iterator p;
while(1){
if(++i > n)i=1;
if(re.size()==0){
puts("D");
return 0;
}
if(de.size()==0){
puts("R");
return 0;
}
if(r[i]){
p = lower_bound(de.begin(),de.end(),i);
if(p != de.end()){
d[ *p ] = 0;
de.erase(p);
}else{
if(de.size()>0){
d[ *de.begin() ] = 0;
de.erase(de.begin());
}
}
}else if(d[i]){
p = lower_bound(re.begin(),re.end(),i);
if(p != re.end()){
r[ *p ] = 0;
re.erase(p);
}else{
if(re.size()>0){
r[ *re.begin() ] = 0;
re.erase(re.begin());
}
}
}
}
return 0;
}
其實這題想明白一點就能做了,兩隊分別用兩個佇列存vote的時間,顯然隊首小的先投,肯定是投死對面隊首的比較有利,然後自己加入回隊尾,注意加入隊尾時時間要加n輪,代表自己投死對面隊首後隔n輪才能再投(如果還合法的話),那會不會對手把自己投死但自己還在佇列中這種情況出現呢?顯然不會,因為是理智的,所以肯定都會先投對面隊首的,如果你出現在隊首說明對手對你的隊伍的選擇優先的只有你了,即你出現就是合理的
想明白就很好寫了,時間31ms
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 200050;
char s[maxn];
queue<int> de,re;
int main()
{
int n;
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;++i){
if(s[i]=='D')
de.push(i);
else
re.push(i);
}
while(1){
if(re.empty()){
puts("D");
return 0;
}
if(de.empty()){
puts("R");
return 0;
}
if(de.front() < re.front()){//D votes
re.pop();
de.push(de.front()+n);
de.pop();
}else{//R votes
de.pop();
re.push(re.front()+n);
re.pop();
}
}
return 0;
}