noip 模拟 31

T1 Game

首先考试想到的直接找大于他最小的数,但按照最大字典序输出就炸了,但前几个数据比较水,得了几分辛苦分

这里我们用线段树维护现行答案:

struct TREE_TABLE {
    #define lid (id<<1)
    #define rid (id<<1|1)
    struct TREE { int numa,numb,ans; } tre[maxn<<2];
    inline void update(int id) { 
        int d=min(tre[lid].numa,tre[rid].numb);
        tre[id].ans=tre[lid].ans+tre[rid].ans+d;
        tre[id].numa=tre[lid].numa+tre[rid].numa-d;
	tre[id].numb=tre[lid].numb+tre[rid].numb-d;
    }
    inline void insert(int id,int l,int r,int pos,int val1,int val2) {
    	if(l==r) { tre[id].numa+=val1; tre[id].numb+=val2; return; }
    	int mid=(l+r)>>1;
	if(pos<=mid) insert(lid,l,mid,pos,val1,val2);
	else insert(rid,mid+1,r,pos,val1,val2);
	update(id);
    }
} tres;

应该很好理解。

然后的话,直接从左向右扫一边,看这个点能否在不改变总答案的前提下被匹配,如果可以那就匹配他,否则就找不能匹配他最大的数且不改变总答案的数,容易发现选择匹配数具有单调性,二分即可。

for(re int i=1,l,r,mid,ans;i<=n;i++) {
	tres.insert(1,1,maxn,a[i],-1,0);
	ans=0,l=a[i]+1,r=*s.rbegin();
		while(l<=r) {
			mid=(l+r)>>1;
			tres.insert(1,1,maxn,mid,0,-1);
			if(tres.tre[1].ans+1==res) l=mid+1,ans=mid;
			else r=mid-1;
			tres.insert(1,1,maxn,mid,0,1);
		}
		tres.insert(1,1,maxn,ans,0,-1);
		if(ans&&tres.tre[1].ans+1==res) { res--; printf("%d ",ans); s.erase(s.find(ans)); }
		else {
			tres.insert(1,1,maxn,ans,0,1);
			ans=0,l=1,r=a[i];
			while(l<=r) {
				mid=(l+r)>>1;
				tres.insert(1,1,maxn,mid,0,-1);
				if(res==tres.tre[1].ans) l=mid+1,ans=mid;
				else r=mid-1;
				tres.insert(1,1,maxn,mid,0,1);
			}
			tres.insert(1,1,maxn,ans,0,-1);
			printf("%d ",ans);
			s.erase(s.find(ans));
		}
	}

T2 Time

考试依然想了个假的正解,数据依然水。。。

采用分治思想,从小到大枚举数字让他们向两边移,采取最优决策就好了,这道题还是比较水的,赶紧过

T3 Cover

很新奇~只有包含和不相交,直接建树

struct DATE { int ls,rs,val; } dat[maxn];
inline bool cmp(DATE a,DATE b) { if(a.ls!=b.ls) return a.ls<b.ls; return a.rs>b.rs; } 
signed main(void) {
  	sort(dat+1,dat+1+m,cmp);
  	vector<int>q; q.push_back(0); 
	for(re int i=1;i<=m;i++) {
		while(q.back()&&dat[q.back()].rs<dat[i].rs) q.pop_back();
		add(q.back(),i);
		q.push_back(i);
	}
}

暴力跳过

重点不在建树,我们发现DP数组可以维护一个差分结构,为什么还取个“差分表”的名字

而且差分数具有单调性,因为这行代码:

f[i][j]=max(f[i][j],f[i][j-1]+dat[i].val);

这地方着重理解,然后mulitset维护差分表,合并时启发式合并(即以小并大)。

posted @ 2021-08-06 08:25  zJx-Lm  阅读(34)  评论(0编辑  收藏  举报