Noip模拟59 2021.9.22

2023-05-13,,

新机房首模拟变倒数

T1 柱状图

关于每一个点可以做出两条斜率分别为$1,-1$的直线,

然后题意转化为移动最少的步数使得所有点都在某一个点的两条直线上

二分出直线的高度,判断条件是尽量让这条直线上部的点和下部的点个数尽量相等

这一部分直接使用动态开点线段树维护即可,

具体实现是每个点左右两边分别维护一棵树,开始的时候吧所有点都放在右边树上

然后扫每一个点作为最高柱子的情况,同事把右树上的点移动到左树上

 1 #include<bits/stdc++.h>
2 #define LL long long
3 using namespace std;
4 namespace AE86{
5 inline int read(){
6 int x=0,f=1;char ch=getchar();
7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
9 }inline void write(LL x,char opt='\n'){
10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14
15 const int NN=1e5+5;
16 int n,h[NN];
17 int L=-1e6,R=1e9+1e6,maxn,id;
18 LL ans=1e18;
19 struct SNOWtree{
20 int ls[NN*30],rs[NN*30],seg,rt;
21 LL sum[NN*30];int siz[NN*30];
22 inline void pushup(int x){
23 sum[x]=sum[ls[x]]+sum[rs[x]];
24 siz[x]=siz[ls[x]]+siz[rs[x]];
25 return;
26 }
27 inline void insert(int &x,int l,int r,int pos,int v){
28 if(!x) x=++seg;
29 if(l==r){
30 sum[x]+=1ll*v*pos; siz[x]+=v; return;
31 } int mid=(l+r)/2; if(mid<=0 && l<0) --mid;
32 if(pos<=mid) insert(ls[x],l,mid,pos,v);
33 else insert(rs[x],mid+1,r,pos,v);
34 pushup(x);
35 }
36 inline int query_siz(int x,int l,int r,int ql,int qr){
37 if(!x) return 0;
38 if(ql<=l && r<=qr) return siz[x];
39 int mid=(l+r)/2,ans=0; if(mid<=0 && l<0) --mid;
40 if(ql<=mid) ans+=query_siz(ls[x],l,mid,ql,qr);
41 if(qr>mid) ans+=query_siz(rs[x],mid+1,r,ql,qr);
42 return ans;
43 }
44 inline LL query_sum(int x,int l,int r,int ql,int qr){
45 if(!x) return 0;
46 if(ql<=l && r<=qr) return sum[x];
47 int mid=(l+r)/2;LL ans=0; if(mid<=0 && l<0) --mid;
48 if(ql<=mid) ans+=1ll*query_sum(ls[x],l,mid,ql,qr);
49 if(qr>mid) ans+=1ll*query_sum(rs[x],mid+1,r,ql,qr);
50 return ans;
51 }
52 }le,ri;
53 inline LL get(int h,int i){
54 LL ans=0;
55 ans+=1ll*le.query_siz(le.rt,L,R,L,h-i-1)*(h-i)-le.query_sum(le.rt,L,R,L,h-i-1);
56 ans+=1ll*ri.query_siz(ri.rt,L,R,L,h+i-1)*(h+i)-ri.query_sum(ri.rt,L,R,L,h+i-1);
57 ans+=le.query_sum(le.rt,L,R,h-i+1,R)-1ll*le.query_siz(le.rt,L,R,h-i+1,R)*(h-i);
58 ans+=ri.query_sum(ri.rt,L,R,h+i+1,R)-1ll*ri.query_siz(ri.rt,L,R,h+i+1,R)*(h+i);
59 return ans;
60 }
61 namespace WSN{
62 inline short main(){
63 freopen("c.in","r",stdin);
64 freopen("c.out","w",stdout);
65 n=read(); for(int i=1;i<=n;i++){
66 h[i]=read();ri.insert(ri.rt,L,R,h[i]+i,1);
67 if(maxn<h[i]) maxn=h[i],id=i;
68 }
69 for(int i=1;i<=n;i++){
70 le.insert(le.rt,L,R,h[i]-i,1);
71 ri.insert(ri.rt,L,R,h[i]+i,-1);
72 int l=max(n-i+1,i),r=max(l,maxn+abs(id-i)),LS,RS;
73 while(l+1<r){
74 int mid=(l+r)>>1;
75 LS=le.query_siz(le.rt,L,R,L,mid-i-1)+ri.query_siz(ri.rt,L,R,L,mid+i-1);
76 RS=n-LS; if(LS<=RS) l=mid; else r=mid;
77 }
78 ans=min(ans,min(get(l,i),get(r,i)));
79 }
80 write(ans);
81 return 0;
82 }
83 }
84 signed main(){return WSN::main();}

T2 应急棍

比较烦这种为了找规律去找规律的题

安置点的规则不用说,就是模拟,然后判断点的位置的时候

我是用$(2_{i-1}+1)^2+1$算出每一层起始点的编号然后一列一列的跳

细节不少,还是模拟,还要高精,所以很烦,(但我没写高精)

 1 #include<bits/stdc++.h>
2 #define int long long
3 using namespace std;
4 int n,T,C;
5 double l;
6 namespace WSN{
7 inline short main(){
8 freopen("a.in","r",stdin);
9 freopen("a.out","w",stdout);
10 cin>>C>>T>>l;
11 while(T--){
12 int n; scanf("%lld",&n);
13 if(n==1) printf("0 0\n");
14 if(n==3) printf("0 %.10lf\n",l);
15 if(n==4) printf("%.10lf 0\n",l);
16 if(n==2) printf("%.10lf %.10lf\n",l,l);
17 if(n<=4) continue; int i=0;
18 while(n-((pow(2,i-1)+1)*(pow(2,i-1)+1)+1)>=0) ++i; --i;
19 n-=((pow(2,i-1)+1)*(pow(2,i-1)+1)+1);
20 double dis=l/pow(2,i);
21 if(!n){printf("%.10lf %.10lf\n",dis,dis);continue;}
22 if(n-pow(4,i-1)+1<=0){
23 double x=n/(int)pow(2,i-1)*dis*2+dis;
24 double y=n%(int)pow(2,i-1)*dis*2+dis;
25 printf("%.10lf %.10lf\n",x,y);
26 }else{
27 int tot=pow(2,i-1)*2+1; n-=pow(4,i-1);
28 // cout<<n<<endl;
29 double x=n/tot*dis*2,y=0;
30 if(n%tot<(int)pow(2,i-1)) y=dis+(n%tot)*dis*2;
31 else x+=dis,y=(n%tot-(int)pow(2,i-1))*dis*2;
32 printf("%.10lf %.10lf\n",x,y);
33 }
34 }
35 return 0;
36 }
37 }
38 signed main(){return WSN::main();}

T3 擒敌拳

李超线段树好题,在这里说一下李超线段树。

这个线段树是真的线段树,他的每个区间维护的是一段线段

$l,r,k,b$其中$k,b$是线段的信息

以维护几条线段的最大值为例来说

开始建树的时候先插入一条斜率为$0$,截距为负无穷的线段

然后要插入你需要维护的线段的时候,分几种情况

1.原来的最大值线段被完爆,直接替换

2.两个线段有交叉,就向交叉部分递归

查询的时候按照标记永久化的思想,走一步查一步

那么这道题可以先用单调栈预处理出每一个矩形为最低矩形的左右边界,

发现每个矩形再他的区间内做贡献是一个一次函数,那么直接使用李超线段树维护即可

 1 #include<bits/stdc++.h>
2 #define int long long
3 #define lid (id<<1)
4 #define rid (id<<1|1)
5 using namespace std;
6 namespace AE86{
7 inline int read(){
8 int x=0,f=1;char ch=getchar();
9 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
10 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
11 }inline void write(int x,char opt='\n'){
12 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
13 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
14 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
15 }using namespace AE86;
16
17 const int NN=200005;
18 int n,h[NN],stk[NN],top,ll[NN],rr[NN],ans[NN];
19 struct seg{
20 int l,r,k,b;
21 int calc(int x){return k*x+b;}
22 int cross(seg x){return (b-x.b)/(x.k-k);}
23 }tr[NN<<2];
24 inline void build(int id,int l,int r){
25 tr[id]=(seg){1,n,0,(int)-1e18};
26 if(l==r) return; int mid=l+r>>1;
27 build(lid,l,mid); build(rid,mid+1,r);
28 }
29 inline void insert(int id,int l,int r,seg x){
30 if(l==r){
31 if(tr[id].calc(l)<x.calc(l)) tr[id]=x;
32 return;
33 }
34 if(x.l<=l&&r<=x.r){
35 if(tr[id].calc(l)<=x.calc(l)&&tr[id].calc(r)<=x.calc(r)) tr[id]=x;
36 else if(tr[id].calc(l)<=x.calc(l)||tr[id].calc(r)<=x.calc(r)){
37 int mid=l+r>>1;
38 if(tr[id].calc(mid)<x.calc(mid)) swap(tr[id],x);
39 if(tr[id].cross(x)<=mid) insert(lid,l,mid,x);
40 if(tr[id].cross(x)>=mid) insert(rid,mid+1,r,x);
41 }
42 }
43 else{
44 int mid=l+r>>1;
45 if(x.l<=mid) insert(lid,l,mid,x);
46 if(x.r>mid) insert(rid,mid+1,r,x);
47 }
48 }
49 inline int query(int id,int l,int r,int pos){
50 if(l==r) return tr[id].calc(pos);
51 int ans=tr[id].calc(pos),mid=l+r>>1;
52 if(pos<=mid) return max(ans,query(lid,l,mid,pos));
53 else return max(ans,query(rid,mid+1,r,pos));
54 }
55 namespace WSN{
56 inline short main(){
57 freopen("b.in","r",stdin);
58 freopen("b.out","w",stdout);
59 n=read(); for(int i=1;i<=n;i++) h[i]=read();
60 build(1,1,n);
61 for(int i=1;i<=n;i++){
62 while(top && h[stk[top]]>h[i]) rr[stk[top--]]=i-1;
63 stk[++top]=i;
64 }
65 while(top) rr[stk[top--]]=n; top=0;
66 for(int i=n;i;i--){
67 while(top && h[stk[top]]>h[i]) ll[stk[top--]]=i;
68 stk[++top]=i;
69 }
70 for(int i=1;i<=n;i++){
71 insert(1,1,n,(seg){i,rr[i],h[i],-h[i]*ll[i]});
72 ans[i]=max(ans[i-1],query(1,1,n,i));
73 }
74 for(int i=1;i<=n;i++) write(ans[i],' ');cout<<endl;
75 return 0;
76 }
77 }
78 signed main(){return WSN::main();}

T4 边数

咕咕咕

Noip模拟59 2021.9.22的相关教程结束。

《Noip模拟59 2021.9.22.doc》

下载本文的Word格式文档,以方便收藏与打印。