zoukankan      html  css  js  c++  java
  • 题解[Loj2727舞会]

    题意描述

    (n)个数,其中有(m)个位置的数是确定的,另外的数随意排列。每次操作把最前面三个数取出,把它们的中位数取出来放到最后,然后删掉这三个数。通过合适的排列,使最后留下来的数最大。

    Sol

    首先这类有关中位数的问题,可以二分后转化为操作(01)序列的问题。每次二分一个有可能的答案(mid),把(>=mid)换成一,(<mid)的数换成零,位置确定的直接换,位置没确定的统计一的个数,考虑(DP)解决。

    注意到每个位置对应的下一步操作呈现出树的结构,三叉树。简单来说,我们可以每次新建一个节点(从(n+1)开始),这个节点的三个儿子就是序列前三个数的位置,反复操作,直到建出根节点。

    (dp[i])(i)节点若要能合成(1)(满足最后剩下的数(>=mid))最少需要的“1”的个数。那转移的时候,就只要先把三个儿子的(dp)求出来,因为只要有两个儿子的变成(1) ,父节点就可以变成(1),所以选儿子中较小的两个就可以啦。

    Code

    #include<bits/stdc++.h>
    #define N (200010)
    using namespace std;
    int n,m,tot,ans,q[N],a[N],pos[N],st[N];
    int s1[N],s2[N],s3[N],dp[N];
    inline int read(){
    	int w=0;
    	char ch=getchar();
    	while(ch>'9'||ch<'0') ch=getchar();
    	while(ch>='0'&&ch<='9'){
    		w=(w<<3)+(w<<1)+(ch^48);
    		ch=getchar();
    	}
    	return w;
    }
    inline void build(int num){
    	tot=num;
    	for(int i=0;i<=num-1;i++) q[i]=i+1;
    	while(num!=1){
    		int left=num%3,now,next=0;
    		for(now=0;now<num-left;now+=3){
    			++tot;
    			s1[tot]=q[now];
    			s2[tot]=q[now+1];
    			s3[tot]=q[now+2];
    			q[left+next]=tot;
    			next++;
    		}
    		for(int i=0;now<num;now++,i++) q[i]=q[now];
    		num=num%3+num/3;
    	}
      //建树
    	return;
    }
    inline void dfs(int x){
    	if(x<=n) return;
    	dfs(s1[x]),dfs(s2[x]),dfs(s3[x]);
    	dp[x]=dp[s1[x]]+dp[s2[x]]+dp[s3[x]]-max(dp[s1[x]],max(dp[s2[x]],dp[s3[x]]));
    	return;
    }
    inline bool judge(int val){
    	int pd=0;//provide
    	for(int i=m+1;i<=n;i++) if(a[i]>=val) pd++;
    	for(int i=1;i<=n;i++) dp[i]=1;
    	for(int i=1;i<=m;i++){
    		if(a[i]>=val) dp[pos[i]]=0;//已经可以了
    		else dp[pos[i]]=1e7;//还不行
    	}
    	dfs(tot);//dp根节点
    	return dp[tot]<=pd;//看根节点需要的1的数量是否小于提供的1的数量
    }
    int main(){
    	n=read(),m=read();
    	build(n);
    	for(int i=1;i<=m;i++) st[i]=a[i]=read(),pos[i]=read();
    	for(int i=m+1;i<=n;i++) st[i]=a[i]=read();
    	sort(st+1,st+1+n);
    	int l=1,r=n;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(judge(st[mid])) l=mid+1,ans=st[mid];
    		else r=mid-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    完结撒花❀

  • 相关阅读:
    内置函数详解
    lambda函数
    第八章(5)
    第八章(4)
    第八章(3)
    第八章(2)
    第八章(1)
    第七章(3)
    第七章(2)
    第七章(1)
  • 原文地址:https://www.cnblogs.com/xxbbkk/p/14431317.html
Copyright © 2011-2022 走看看