题解 P1878 【舞蹈课】

· · 题解

这道题

是暑假的时候教练给我们测试的一道题,说实话,当时没打完,究其原因,竟是我代码能力太差了思路太复杂了qwq

但是,尽管思路比较清奇,我也觉得可能会有和我想的一样但是代码打不出来的人,所以我要发一发题解来帮帮大伙

题解里面有打上标记的,而可以说用的不是 bool 类型的标记而是 int 类型的标记

我们大部分人自然都知道优先队列(大根/小根堆),这里不再赘述,就给个链接

下面进入问答环节:

$ANSWER:$ 其实想想也不难,只要用优先队列来维护相邻舞者之间的技术值的差,每次取最小的就OK了 $ASK:$ 有一对跳了之后,TA们两边的怎么办? $ANSWER:$ 这个问题其实也不算难,我们只要用链表结构,断链重连,放入队列就好了 ~~问答环节结束~~ ------------ 看到这儿,可能你就跑去打代码了对吧,但是,停下!!! ~~(当然你真的会了你自然可以走了我不留你~~ 但是还有一个比较重要的问题: 对于一排舞者,B1 G1 B2 G2 ,我们一开始存储并放入队列的是什么,是每两个相邻的舞者的差,那假设 G1 B2 先出来,然后断链重连,那么B1 G1 的联系以及 B2 G2 的联系该怎么办??? 这时候,我们就要学会打标记了。 ------------ ### 我们有两种可选的思路: **第一种**比较简单,即在每一对舞者出列之后对这两个舞者都打上标记,以后在优先队列中取出TA们的时候不执行操作就是了 **第二种**则有点~~蠢~~难,就是在每次更新差值的时候,用int数组存放更新了的差值,如果在后面从优先队列中取出的差值与之前存放的差值不相等的话,则说明这个差值未被更新的,那也不执行操作即可 ~~(第二种是我这种菜鸡用的方法,看不太懂就学第一个吧)~~ ------------ #### 代码来了: 1.第一种的之前题解似乎有 2.第二种: ```cpp #include<iostream> #include<cstdio> #include<queue> #include<cmath> using namespace std; #define inf 2000000000 int ans[200005][2],sum=0; struct node//链表 { int l,r,cha,xu; bool judge; }a[200005]; bool operator<(node rr,node ll)//优先队列有限法则 { int lll=abs(ll.cha),rrr=abs(rr.cha); if(rrr!=lll) return lll<rrr; else return ll.xu<rr.xu; } priority_queue <node> que; int main ( ) { //freopen("dance.in","r",stdin); //freopen("dance.out","w",stdout); int n,now,next,t=0; char x; scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>x; if(x=='B') a[i].judge=0; else a[i].judge=1; } //以上性别判断 scanf("%d",&now); for(int i=1;i<n;i++) { scanf("%d",&next); a[i].xu=i; //自身是第几个 a[i].cha=next-now;//预处理技术值差 a[i].l=i-1;a[i].r=i+1;//预处理左右 que.push(a[i]); now=next; } a[n].r=n+1;a[n].xu=n;a[n].cha=inf; while(!que.empty())//开始模拟过程 { int xx=que.top().xu,cmp=que.top().cha; que.pop(); int yy=a[xx].r; if(a[xx].cha==cmp/*判断是否是更新过的*/&&a[xx].judge!=a[yy].judge/*一男一女*/ &&xx!=0&&yy!=n+1/*特判链表首尾 */) { ans[++t][0]=xx;ans[t][1]=yy; a[a[xx].l].cha+=a[xx].cha+a[yy].cha;//更新差值 a[a[yy].r].l=a[xx].l;a[a[xx].l].r=a[yy].r;//断链重连 if(a[xx].l>0&&a[yy].r<=n)//特判链表首尾 que.push(a[a[xx].l]);//入队列 a[xx].l=a[xx].r=0;a[yy].l=a[yy].r=n+1; } } printf("%d\n",t); for(int i=1;i<=t;i++) printf("%d %d\n",ans[i][0],ans[i][1]); return 0; } ``` 写了好久。。。求管理大大通过;求读者赞赞。