A Game with Colored Balls 郁闷,一个早上加一个晚上=Wa (再加一早上 AC)

 

#include<iostream>

#include<algorithm>

#include<string.h>

#include<stack>

#include<set>

 

using namespace std;

#define N 10000002

 

struct node

{

char ch;

int pos,num,pre,next;

friend bool operator<(node a,node b)

{

if(a.num==b.num)

return a.pos<b.pos;

else

return a.num>b.num;

}

};

struct sun

{

int pos,pre,next;

};

 

node dia[N+1],tt,pp;

char s[N+1];

set<node> S;

set<node>::iterator it;

sun G[N+1],R[N+1],B[N+1];

int gn,rn,bn,cnt;

 

void print(int num)

{

int i,j;

for(i=0;i<num;i++)

cout<<dia[i].ch<<dia[i].num<<endl;

}

void init()

{

int i;

for(i=1;i<gn;i++)

G[i-1].next=i;

G[gn-1].next=N;

for(i=1;i<rn;i++)

R[i-1].next=i;

R[rn-1].next=N;

for(i=1;i<bn;i++)

B[i-1].next=i;

B[bn-1].next=N;

}

 

int finds(sun ri[],int num,int end)

{

int low=0,high=num-1,mid;

while(low<high)

{

mid=(low+high)>>1;

if(ri[mid].pos==end)

return mid;

else if(ri[mid].pos<end)

low=mid+1;

else

high=mid-1;

}

}

int main()

{

int i,n,temp,end,fuck;

char ch;//int test=0;

stack<int>res;

while(scanf("%s",s)!=EOF)

{//while(test);test++;

n=strlen(s);

gn=rn=bn=cnt=0;

for(i=0;i<n;i++)

{

ch=s[i];

temp=i;

if(ch=='G')

{

if(gn==0)

G[gn].pre=-1;

else

G[gn].pre=gn-1;

G[gn++].pos=i;

}

else if(ch=='R')

{

if(rn==0)

R[rn].pre=-1;

else

R[rn].pre=rn-1;

R[rn++].pos=i;

}

else

{

if(bn==0)

B[bn].pre=-1;

else

B[bn].pre=bn-1;

B[bn++].pos=i;

}

while(i+1<n&&s[i+1]==s[temp])

{

i++;

if(ch=='G')

{

G[gn].pre=gn-1;

G[gn++].pos=i;

}

else if(ch=='R')

{

R[rn].pre=rn-1;

R[rn++].pos=i;

}

else

{

B[bn].pre=bn-1;

B[bn++].pos=i;

}

 

}

dia[cnt].pos=i;

dia[cnt].num=i-temp+1;

dia[cnt].ch=ch;

dia[cnt].pre=cnt-1;

dia[cnt].next=cnt+1;

S.insert(dia[cnt]);

cnt ++;

}

init();

//print(cnt);

int now,start;

while(S.size()!=0)

{

it=S.begin();

end=(*it).pos;

ch=(*it).ch;

temp=(*it).num;

if(temp==1)

break;

if(ch=='G')

{

printf("G");

end=finds(G,gn,end);

start=G[end].next;

for(i=end;temp!=0;i=G[i].pre)

{

temp--;

res.push(i);

}

if(i!=-1)

G[i].next=start;

if(start!=N)

G[start].pre=i;

while(!res.empty())

{

now=res.top();

res.pop();

printf(" %d",G[now].pos+1);

}

printf("/n");

}

else if(ch=='R')

{

printf("R");

end=finds(R,rn,end);

start=R[end].next;

for(i=end;temp!=0;i=R[i].pre)

{

temp--;

res.push(i);

}

if(i!=-1)

R[i].next=start;

if(start!=N)

R[start].pre=i;

while(!res.empty())

{

now=res.top();

res.pop();

printf(" %d",R[now].pos+1);

}

printf("/n");

}

else

{

printf("B");

end=finds(B,bn,end);

start=B[end].next;

for(i=end;temp!=0;i=B[i].pre)

{

temp--;

res.push(i);

}

if(i!=-1)

B[i].next=start;

if(start!=N)

B[start].pre=i;

while(!res.empty())

{

now=res.top();

res.pop();

printf(" %d",B[now].pos+1);

}

printf("/n");

}

if((*it).next!=cnt&&(*it).pre!=-1)

{

tt=dia[(*it).next];

pp=dia[(*it).pre];

S.erase(tt);

S.erase(pp);

if(tt.ch==pp.ch)

{

tt.pre=pp.pre;

tt.num+=pp.num;

if(pp.pre!=-1)

{

fuck=pp.pre;

pp=dia[fuck];

S.erase(pp);

dia[fuck].next=(*it).next;

S.insert(dia[fuck]);

}

dia[(*it).next]=tt;

S.insert(tt);

}

else

{

dia[(*it).next].pre=(*it).pre;

S.insert(dia[(*it).next]);

dia[(*it).pre].next=(*it).next;

S.insert(dia[(*it).pre]);

}

}

else 

{

if((*it).next==cnt&&(*it).pre!=-1)

{

pp=dia[(*it).pre];

S.erase(pp);

pp.next=cnt;

dia[(*it).pre].next=cnt;

S.insert(pp);

}

if((*it).next!=cnt&&(*it).pre==-1)

{

tt=dia[(*it).next];

S.erase(tt);

tt.pre=-1;

dia[(*it).next].pre=-1;

S.insert(tt);

}

}

 

S.erase(*it);

}

S.clear();

}

return 0;

}

先说说思路吧:

给定一串字符串 GRRBBBRRGB,从左边起选出最长的连续子串,如这个子串长度为0,直接退出。否则,将子串删除,若子串不在两端,

则要把剩下的两段合并起来作为新的母串,并返回循环,很显然我们只要开个结构体,在预处理的时候把连在一起的作为一份子,记录个数和

终点(或者起点位置),并记录下相邻的编号,若是第一个,则它的前面编号可以定-1,如是最后一个,则它的后继可以定无穷,然后重载下<号,以个数大为优先,个数一样情况下终点(起点)位置在前优先;然后每次从堆里取出最优的,并处理取出后调整的新情况。

一:若取出的是在两端,(是新串的第一个,即前继为-1,则把它的后继的前继变为-1,若是最后一个,情况类同处理)

二:若取出的是在中间,则分两种情况(1,若它的前继和它的后继是同一个字母,则合并,一点很重要,不要忘记前继的前继的后继将会变成当前取出的后继(倘若前继的前继不是-1),并把它的前继的位置给标记掉。2若它的前继和它的后继不是同一个字母,那只要改变下前继的后继变成它的后继,它的后继的前继变成我的前继)并把更新过的都要重新放回堆里面。堆里面那些垃圾(就是不是最新的信息是不能用的)。

原本打算用set做的,因为中途要不断更改信息,想把错误的信息中set里面删除,但是频繁的删除插入的效果就不在等价于log2(n)了,于是

悲剧诞生了。

后面采用了优先队列,不采取删除,采取标记和比较,若弹出的信息不是最新的就直接pop;然后就是照上面思路YY一下就行了。

Problem: 3476 User: hd_james
Memory: 71340K Time: 1750MS
Language: C++ Result: Accepted

 

#include<iostream>

#include<algorithm>

#include<string.h>

#include<stack>

#include<set>

#include<queue>

 

using namespace std;

#define N 10000002

 

struct node

{

char ch;

int pos,num,pre,next,loc;

friend bool operator<(node a,node b)

{

if(a.num==b.num)

return a.pos>b.pos;

else

return a.num<b.num;

}

};

struct sun

{

int pos,pre,next;

};

 

node dia[N+1],tt,pp;

char s[N+1];

//set<node> S;

node it;

priority_queue<node> Q;

sun G[N+1],R[N+1],B[N+1];

int gn,rn,bn,cnt,res[N+1];

bool flag[N+1];

 

// void print(int num)

// {

// int i,j;

// for(i=0;i<num;i++)

// cout<<dia[i].ch<<dia[i].num<<endl;

// }

void init()

{

int i;

for(i=1;i<gn;i++)

G[i-1].next=i;

G[gn-1].next=N;

for(i=1;i<rn;i++)

R[i-1].next=i;

R[rn-1].next=N;

for(i=1;i<bn;i++)

B[i-1].next=i;

B[bn-1].next=N;        

}

 

int finds(sun ri[],int num,int end)

{

int low=0,high=num-1,mid;

while(low<=high)

{

mid=(low+high)>>1;

if(ri[mid].pos==end)

return mid;

else if(ri[mid].pos<end)

low=mid+1;

else

high=mid-1;

}

}

int main()

{

int i,n,temp,end,fuck;

char ch;//int test=0;

int cao=0;

// freopen("1.in","r",stdin);

//freopen("1.out","w",stdout);

scanf("%s",s);

//gets(s);

{//while(test);test++;

memset(flag,false,sizeof(flag));

n=strlen(s);

gn=rn=bn=cnt=0;

for(i=0;i<n;i++)

{

ch=s[i];

temp=i;

if(ch=='G')

{

if(gn==0)

G[gn].pre=-1;

else

G[gn].pre=gn-1;

G[gn++].pos=i;

}

else if(ch=='R')

{

if(rn==0)

R[rn].pre=-1;

else

R[rn].pre=rn-1;

R[rn++].pos=i;

}

else

{

if(bn==0)

B[bn].pre=-1;

else

B[bn].pre=bn-1;

B[bn++].pos=i;

}

while(i+1<n&&s[i+1]==s[temp])

{

i++;

if(ch=='G')

{

G[gn].pre=gn-1;

G[gn++].pos=i;

}

else if(ch=='R')

{

R[rn].pre=rn-1;

R[rn++].pos=i;

}

else

{

B[bn].pre=bn-1;

B[bn++].pos=i;

}

 

}

dia[cnt].pos=i;

dia[cnt].num=i-temp+1;

dia[cnt].ch=ch;

dia[cnt].pre=cnt-1;

dia[cnt].next=cnt+1;

dia[cnt].loc=cnt;

//S.insert(dia[cnt]);

Q.push(dia[cnt]);

cnt ++;

}

init();

//print(cnt);

int now,start;

while(!Q.empty())

{

it=Q.top();

Q.pop();

end=it.pos;

ch=it.ch;

temp=it.num;

if(temp==1)

break;

if(flag[end])

continue;

if(dia[it.loc].pre!=it.pre||dia[it.loc].next!=it.next||dia[it.loc].num!=it.num)

continue;

if(ch=='G')

{

printf("G");

end=finds(G,gn,end);

start=G[end].next;

cao=0;

for(i=end;temp!=0;i=G[i].pre)

{

temp--;

//res.push(i);

res[cao++]=i;

}

if(i!=-1)

G[i].next=start;

if(start!=N)

G[start].pre=i;

for(i=cao-1;i>=0;i--)

{

now=res[i];

flag[G[now].pos]=true;

printf(" %d",G[now].pos+1);

}

printf("/n");

}

else if(ch=='R')

{

printf("R");

end=finds(R,rn,end);

start=R[end].next;

cao=0;

for(i=end;temp!=0;i=R[i].pre)

{

temp--;

//res.push(i);

res[cao++]=i;

}

if(i!=-1)

R[i].next=start;

if(start!=N)

R[start].pre=i;

for(i=cao-1;i>=0;i--)

{

now=res[i];

flag[R[now].pos]=true;

printf(" %d",R[now].pos+1);

}

printf("/n");

}

else

{

printf("B");

end=finds(B,bn,end);

start=B[end].next;

cao=0;

for(i=end;temp!=0;i=B[i].pre)

{

temp--;

//res.push(i);

res[cao++]=i;

}

if(i!=-1)

B[i].next=start;

if(start!=N)

B[start].pre=i;

for(i=cao-1;i>=0;i--)

{

now=res[i];

flag[B[now].pos]=true;

printf(" %d",B[now].pos+1);

}

printf("/n");

}

if(it.next!=cnt&&it.pre!=-1)

{

tt=dia[it.next];

pp=dia[it.pre];

//S.erase(tt);

//S.erase(pp);

if(tt.ch==pp.ch)

{

tt.pre=pp.pre;

tt.num+=pp.num;

dia[tt.loc]=tt;

Q.push(tt);

if(pp.pre!=-1)

{

flag[pp.pos]=true;

fuck=pp.pre;

pp=dia[fuck];

dia[fuck].next=it.next;            

Q.push(dia[fuck]);

}            

//dia[it.next]=tt;

}

else

{

dia[it.next].pre=it.pre;

dia[it.pre].next=it.next;

Q.push(dia[it.next]);

Q.push(dia[it.pre]);

}

}

else 

{

if(it.next==cnt&&it.pre!=-1)

{

dia[it.pre].next=cnt;

Q.push(dia[it.pre]);

}

if(it.next!=cnt&&it.pre==-1)

{

dia[it.next].pre=-1;

Q.push(dia[it.next]);

}

}

}

}

return 0;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值