ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021.9.22考试总结[NOIP模拟59]

2021-09-24 08:02:58  阅读:158  来源: 互联网

标签:ch 59 22 NOIP int tr pos ht tl


T1 柱状图

关于每个点可以作出两条斜率绝对值为\(1\)的直线。

将绝对值拆开,对在\(i\)左边的点\(j\),\(h_i-i=h_j-j\),右边则是把减号换成加号。

把每个点位置为横坐标,高度与位置的差或和为纵坐标扔到坐标系里,发现每条直线上下点数最接近时代价最小。

对每个点二分即可。

T1
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

namespace IO{
	inline int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	inline void write(LL x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=100010,L=-1e6,R=1e9+1e6;
int n,mx,id,h[NN];
LL ans;

struct segment_tree{
	int tot,root,lc[NN*40],rc[NN*40],siz[NN*40];
	LL sum[NN*40];
	void pushup(int rt){
		siz[rt]=siz[lc[rt]]+siz[rc[rt]];
		sum[rt]=sum[lc[rt]]+sum[rc[rt]];
	}
	void insert(int& rt,int l,int r,int pos,int v){
		if(!rt) rt=++tot;
		if(l==r){ siz[rt]+=v; sum[rt]+=1ll*pos*v; return; }
		int mid=(l+r)/2;
		if(mid<=0&&l<0) --mid;
		if(pos<=mid) insert(lc[rt],l,mid,pos,v);
		else insert(rc[rt],mid+1,r,pos,v);
		pushup(rt);
	}
	int querysz(int rt,int l,int r,int opl,int opr){
		if(!rt) return 0;
		if(l>=opl&&r<=opr) return siz[rt];
		int mid=(l+r)/2,res=0;
		if(mid<=0&&l<0) --mid;
		if(opl<=mid) res+=querysz(lc[rt],l,mid,opl,opr);
		if(opr>mid) res+=querysz(rc[rt],mid+1,r,opl,opr);
		return res;
	}
	LL querysm(int rt,int l,int r,int opl,int opr){
		if(!rt) return 0;
		if(l>=opl&&r<=opr) return sum[rt];
		int mid=(l+r)/2; LL res=0;
		if(mid<=0&&l<0) --mid;
		if(opl<=mid) res+=querysm(lc[rt],l,mid,opl,opr);
		if(opr>mid) res+=querysm(rc[rt],mid+1,r,opl,opr);
		return res;
	}
}tl,tr;

LL getans(int ht,int pos){
	LL res=0;
	res+=1ll*tl.querysz(tl.root,L,R,L,ht-pos-1)*(ht-pos)-tl.querysm(tl.root,L,R,L,ht-pos-1);
	res+=1ll*tr.querysz(tr.root,L,R,L,ht+pos-1)*(ht+pos)-tr.querysm(tr.root,L,R,L,ht+pos-1);
	res+=tl.querysm(tl.root,L,R,ht-pos+1,R)-1ll*tl.querysz(tl.root,L,R,ht-pos+1,R)*(ht-pos);
	res+=tr.querysm(tr.root,L,R,ht+pos+1,R)-1ll*tr.querysz(tr.root,L,R,ht+pos+1,R)*(ht+pos);
//	cout<<ht<<' '<<pos<<' '<<res<<endl;
	return res;
}

signed main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	n=read(); ans=1e18;
	for(int i=1;i<=n;i++){
		h[i]=read();
		if(h[i]>mx) mx=h[i], id=i;
		tr.insert(tr.root,L,R,h[i]+i,1);
	}
	for(int i=1;i<=n;i++){
		tl.insert(tl.root,L,R,h[i]-i, 1);
		tr.insert(tr.root,L,R,h[i]+i,-1);
		int l=max(i,n-i+1),r=max(l,mx+abs(id-i));
		while(l+1<r){
			int mid=l+r>>1;
			int upr=tl.querysz(tl.root,L,R,L,mid-i-1)+tr.querysz(tr.root,L,R,L,mid+i-1);
			int dwn=n-upr;
			if(upr<=dwn) l=mid;
			else r=mid;
		}
		ans=min(ans,min(getans(l,i),getans(r,i)));
	}
	write(ans,'\n');
	return 0;
}

T2 应急棍

随便找规律,发现每次在最小的正方形中从左到右先放中心再放边的中点。

随便写写式子,高精小数是不可能写的。

\(code:\)

T2
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long double DB;

namespace IO{
	inline int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	inline void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

DB l,x,y,len;
int c,t,n,tmp,pw4[31],pw2[64];

signed main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	c=read(); t=read();
	scanf("%Lf",&l);
	pw2[0]=pw4[0]=1;
	for(int i=1;i<31;i++) pw4[i]=pw4[i-1]*4;
	for(int i=1;i<64;i++) pw2[i]=pw2[i-1]*2;
	while(t--){
		n=read();
		if(n==1) printf("%d %d\n",0,0);
		if(n==2) printf("%.10Lf %.10Lf\n",l,l);
		if(n==3) printf("%d %.10Lf\n",0,l);
		if(n==4) printf("%.10Lf %d\n",l,0);
		if(n<5) continue;
		n-=4; tmp=0;//cout<<n<<' '<<pw4[tmp]+2*pw2[tmp]*(pw2[tmp]+1)<<endl;
		while(n-pw4[tmp]-2*pw2[tmp]*(pw2[tmp]+1)>0){
			n-=pw4[tmp]+2*pw2[tmp]*(pw2[tmp]+1);
			++tmp;
		}
		len=l/(DB)pw2[tmp];
		if(n<=pw4[tmp]){
			x=len/2.0+(DB)((n-1)/pw2[tmp])*len;
			y=len/2.0+(DB)((n-1)%pw2[tmp])*len;
			printf("%.10Lf %.10Lf\n",x,y);
			continue;
		}
		else n-=pw4[tmp];
		x=len*(DB)((n-1)/(pw2[tmp+1]+1));//cout<<len<<' '<<x<<' '<<n<<' '<<pw2[tmp+1]<<endl;
		if((n-1)%(pw2[tmp+1]+1)>=pw2[tmp]) x+=len/2.0, y=len*(DB)((n-1)%(pw2[tmp+1]+1)-pw2[tmp]);
		else y=len*(DB)((n-1)%(pw2[tmp+1]+1))+len/2.0;
		printf("%.10Lf %.10Lf\n",x,y);
	}
	return 0;
}

T3 擒敌拳

每个矩形的贡献是关于位置的一次函数。

单调栈维护出矩形最大管辖区间后李超线段树处理。

前两天刚学的东西,真滴NB。

\(code:\)

T3
#include<bits/stdc++.h>
#define int long long
using namespace std;

namespace IO{
	inline int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	inline void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=200010;
int n,top,h[NN],stk[NN],ans[NN],timr[NN],timl[NN];

namespace LC_segtree{
	#define ld rt<<1
	#define rd (rt<<1)|1
	struct segs{
		int l,r,k,b;
		segs(){}
		segs(int a,int e,int c,int d){ l=a; r=e; k=c; b=d; }
		int calc(int pos){ return b+k*pos; }
		int cross(segs x){ return (b-x.b)/(x.k-k); }
	}s[NN<<2];
	void build(int rt,int l,int r){
		s[rt]=segs(1,n,0,-1e18);
		if(l==r) return;
		int mid=l+r>>1;
		build(ld,l,mid);
		build(rd,mid+1,r);
	}
	void insert(int rt,int l,int r,segs v){//cout<<s[rt].k<<' '<<s[rt].b<<' '<<v.k<<' '<<v.b<<' '<<s[rt].calc(l)<<' '<<v.calc(l)<<endl;
		if(l==r){
			if(s[rt].calc(l)<v.calc(l)) s[rt]=v;
			return;
		}
		if(l>=v.l&&r<=v.r){
			if(s[rt].calc(l)<=v.calc(l)&&s[rt].calc(r)<=v.calc(r)) s[rt]=v;
			else if(s[rt].calc(l)<=v.calc(l)||s[rt].calc(r)<=v.calc(r)){
				int mid=l+r>>1;
				if(s[rt].calc(mid)<v.calc(mid)) swap(s[rt],v);
				if(s[rt].cross(v)<=mid) insert(ld,l,mid,v);
				if(s[rt].cross(v)>=mid) insert(rd,mid+1,r,v);
			}
		} else{
			int mid=l+r>>1;
			if(v.l<=mid) insert(ld,l,mid,v);
			if(v.r>mid) insert(rd,mid+1,r,v);
		}
	}
	int query(int rt,int l,int r,int pos){//cout<<pos<<' '<<s[rt].k<<' '<<s[rt].b<<' '<<s[rt].calc(pos)<<endl;
		if(l==r) return s[rt].calc(pos);
		int res=s[rt].calc(pos),mid=l+r>>1;
		if(pos<=mid) return max(res,query(ld,l,mid,pos));
		else return max(res,query(rd,mid+1,r,pos));
	}
} using namespace LC_segtree;

signed main(){
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	n=read(); build(1,1,n);
	for(int i=1;i<=n;i++) h[i]=read();
	for(int i=1;i<=n;i++){
		while(h[stk[top]]>h[i]) timr[stk[top--]]=i-1;
		stk[++top]=i;
	}
	while(top) timr[stk[top--]]=n;
	for(int i=n;i;i--){
		while(h[stk[top]]>h[i]) timl[stk[top--]]=i;
		stk[++top]=i;
	}
	for(int i=1;i<=n;i++){
//		cout<<timl[i]<<' '<<timr[i]<<endl;
		insert(1,1,n,segs(i,timr[i],h[i],-h[i]*timl[i]));
		ans[i]=max(ans[i-1],query(1,1,n,i));
	}
	for(int i=1;i<=n;i++) write(ans[i],i==n?'\n':' ');
	return 0;
}

T4 边数

太弱,待补(根本补不完

标签:ch,59,22,NOIP,int,tr,pos,ht,tl
来源: https://www.cnblogs.com/keeeeeeen/p/15328359.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有