T1 柱状图

解题思路

二分答案+线段树check

显然对于最后的限制,我们希望向上移的和向下移的柱子数尽量接近。

因此枚举每一个柱子当做最高的一个的时刻,二分找到一个当前最优解更新答案。

开两棵线段树分别维护当前柱子左右两侧的柱子的 \(h_i+i\) 和 \(h_i-i\) 每次查询个数用个数以及权值和判断更新即可。

需要卡常,但是我懒直接卡了一下时就走了。。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
#define ls tre[x].l
#define rs tre[x].r
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+10,INF=1e9;
int n,ans=1e18,maxn,s[N];
bool check(){return (1.0*clock())/(1.0*CLOCKS_PER_SEC)<=1.49;}
struct Segment_Tree
{
int root,all;
Segment_Tree(){all=0;root=0;}
struct Node
{
int l,r,siz,dat;
}tre[N*30];
void push_up(int x){tre[x].siz=tre[ls].siz+tre[rs].siz;tre[x].dat=tre[ls].dat+tre[rs].dat;}
void insert(int &x,int l,int r,int pos,int val)
{
if(!x) x=++all;
if(l==r) return tre[x].siz+=val,tre[x].dat=tre[x].siz*l,void();
int mid=floor((1.0*l+1.0*r)/2.0);
if(pos<=mid) insert(ls,l,mid,pos,val);
else insert(rs,mid+1,r,pos,val);
push_up(x);
}
int query_siz(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(L<=l&&r<=R) return tre[x].siz;
int mid=floor((1.0*l+1.0*r)/2.0),sum=0;
if(L<=mid) sum+=query_siz(ls,l,mid,L,R);
if(R>mid) sum+=query_siz(rs,mid+1,r,L,R);
return sum;
}
int query_sum(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(L<=l&&r<=R) return tre[x].dat;
int mid=floor((1.0*l+1.0*r)/2.0),sum=0;
if(L<=mid) sum+=query_sum(ls,l,mid,L,R);
if(R>mid) sum+=query_sum(rs,mid+1,r,L,R);
return sum;
}
}L,R;
int solve(int x,int val)
{
int tmp1=L.query_siz(L.root,-N,INF+N,-N,val-x-1)*(val-x)-L.query_sum(L.root,-N,INF+N,-N,val-x-1);
int tmp2=L.query_sum(L.root,-N,INF+N,val-x+1,INF+N)-L.query_siz(L.root,-N,INF+N,val-x+1,INF+N)*(val-x);
int tmp3=R.query_siz(R.root,-N,INF+N,-N,val+x-1)*(val+x)-R.query_sum(R.root,-N,INF+N,-N,val+x-1);
int tmp4=R.query_sum(R.root,-N,INF+N,val+x+1,INF+N)-R.query_siz(R.root,-N,INF+N,val+x+1,INF+N)*(val+x);
if(tmp1+tmp2+tmp3+tmp4<0) return INF*INF;
return tmp1+tmp2+tmp3+tmp4;
}
signed main()
{
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) s[i]=read(),maxn=max(maxn,s[i]+i);
for(int i=1;i<=n;i++) R.insert(R.root,-N,INF+N,s[i]+i,1);
for(int i=1;i<=n;i++)
{
if(!check()) break;
int l=max(i,n-i+1),r=maxn;
while(l+1<r)
{
int mid=(l+r)>>1;
int temp=L.query_siz(L.root,-N,INF+N,-N,mid-i-1)+R.query_siz(R.root,-N,INF+N,-N,mid+i-1);
if(temp<=n-temp-1) l=mid;
else r=mid;
}
ans=min(ans,min(solve(i,l),solve(i,r)));
R.insert(R.root,-N,INF+N,s[i]+i,-1);
L.insert(L.root,-N,INF+N,s[i]-i,1);
}
printf("%lld",ans);
return 0;
}

T2 应急棍

大坑未补

需要高精小数,并且比较难打,咕了。

T3 擒敌拳

解题思路

李超线段树维护单调栈。

大概是个板子了吧,尽管我刚刚学会,单调栈预处理出某个高度可行的区间,在这个区间中插入一条直线其实就是插入一条线段。

然后对于标记下放的时候记录当前区间比较占优势的线段的斜率截距,也就是区间中点取值较优的一个。

优于我们既想要更新答案又想要同时保留两个值,因此就有一个 swap 的操作。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10,INF=1e18;
int n,top,sta[N],s[N],l[N],r[N];
struct Segment_Tree{int k,b;}tre[N<<2];
int g(int x,int k,int b){return x*k+b;}
void insert(int x,int l,int r,int k,int b)
{
if(g(l,tre[x].k,tre[x].b)<=g(l,k,b)&&g(r,tre[x].k,tre[x].b)<=g(r,k,b)) return tre[x].k=k,tre[x].b=b,void();
if(l==r) return;
int mid=(l+r)>>1;
if(g(mid,tre[x].k,tre[x].b)<=g(mid,k,b)) swap(tre[x].k,k),swap(tre[x].b,b);
if(g(l,tre[x].k,tre[x].b)<=g(l,k,b)) insert(ls,l,mid,k,b);
if(g(r,tre[x].k,tre[x].b)<=g(r,k,b)) insert(rs,mid+1,r,k,b);
}
void update(int x,int l,int r,int L,int R,int k,int b)
{
if(L<=l&&r<=R) return insert(x,l,r,k,b),void();
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R,k,b);
if(R>mid) update(rs,mid+1,r,L,R,k,b);
}
int query(int x,int l,int r,int pos)
{
if(l==r) return g(l,tre[x].k,tre[x].b);
int mid=(l+r)>>1,dat=g(pos,tre[x].k,tre[x].b);
if(pos<=mid) dat=max(dat,query(ls,l,mid,pos));
else dat=max(dat,query(rs,mid+1,r,pos));
return dat;
}
signed main()
{
freopen("b.in","r",stdin); freopen("b.out","w",stdout);
n=read(); for(int i=1;i<=n;i++) s[i]=read(),l[i]=r[i]=i;
for(int i=1;i<=n;i++)
{
while(top&&s[i]<=s[sta[top]]) l[i]=l[sta[top--]];
sta[++top]=i;
}
top=0;
for(int i=n;i>=1;i--)
{
while(top&&s[i]<=s[sta[top]]) r[i]=r[sta[top--]];
sta[++top]=i;
}
for(int i=1,maxn=0;i<=n;i++)
{
update(1,1,n,l[i],r[i],s[i],-(l[i]-1)*s[i]);
printf("%lld ",maxn=max(maxn,query(1,1,n,i)));
}
return 0;
}

T4 连接(边数)

解题思路

显然是一个基环树森林, 1 节点需要向每一个树的叶子节点连边,然后每隔 k 连接一个点。

然后就是处理环的情况,可以倍增跳看全部覆盖之后是否是最优解,也可以枚举每个点在所覆盖的 k 中的位置,对于本题而言复杂度都允许。。。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=5e5+10,INF=1e18;
int n,m,cnt,all,top,ans,tim,sta[N],du[N];
int f[N][25],s[N<<1],near[N<<1],pre[N<<1];
int tot=1,head[N],nxt[N<<1],ver[N<<1];
bool b[N],vis[N],jud[N],suc[N];
set<int> se;
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
du[y]++;
}
void dfs(int x)
{
if(!b[x])
{
b[x]=true; if(vis[x]) return b[x]=false,void();
for(int i=head[x];i;i=nxt[i]) dfs(ver[i]);
b[x]=false; vis[x]=true;
return ;
}
int temp=x; jud[x]=true;
do
{
temp=ver[head[temp]];
jud[temp]=true;
}while(temp!=x);
}
void SPJ()
{
suc[1]=true;
int to=ver[head[1]];
du[to]--; suc[to]=true;
if(se.find(1)!=se.end()) se.erase(1);
if(se.find(to)!=se.end()) se.erase(to);
}
void topo_sort()
{
queue<int> q;
if(!suc[1]) SPJ(),q.push(ver[head[1]]);
for(auto it=se.begin();it!=se.end();it++)
if(!du[(*it)]&&!jud[(*it)]&&!suc[(*it)])
ans++,suc[(*it)]=true,q.push((*it));
while(!q.empty())
{
int x=q.front(),temp=m-1,fro=0; suc[x]=true; q.pop();
while(temp--)
{
fro=x; x=ver[head[x]]; if(!du[fro]) du[x]--; suc[x]=true;
if(!du[fro]&&se.find(fro)!=se.end()) se.erase(fro);
}
fro=x; x=ver[head[x]]; if(!du[fro]) du[x]--;
if(!du[fro]&&se.find(fro)!=se.end()) se.erase(fro);
if(!du[x]&&!jud[x]&&!suc[x]){q.push(x);ans++;suc[x]=true;continue;}
while(!du[x]&&suc[x])
{
if(se.find(x)!=se.end()) se.erase(x);
x=ver[head[x]]; du[x]--;
}
}
}
int solve(int x)
{
int len=0,minn=INF,temp=x;
do
{
temp=ver[head[temp]];
s[++len]=temp;
}while(temp!=x);
for(int i=len+1;i<=2*len;i++) s[i]=s[i-len];
near[2*len+1]=2*len+1; pre[2*len+1]=INF;
for(int i=2*len;i>=1;i--)
if(!suc[s[i]]) near[i]=i;
else near[i]=near[i+1];
for(int i=1;i<=len*2;i++) pre[i]=pre[i-1]+(suc[s[i]]^1);
for(int i=2*len+1;i>=1;i--)
{
f[i][0]=near[min(i+m,len*2+1)];
for(int j=1;j<=20;j++)
f[i][j]=f[f[i][j-1]][j-1];
}
for(int i=1;i<=len;i++)
{
int t=0,pos=i;
for(int j=20;j>=0;j--)
if(f[pos][j]<=i+len) pos=f[pos][j],t+=1ll<<j;
if(pos<=i+len-1&&pre[pos-1]!=pre[i+len]) t++;
minn=min(minn,t);
}
for(int i=1;i<=len;i++) suc[s[i]]=true;
return minn;
}
signed main()
{
freopen("d.in","r",stdin); freopen("d.out","w",stdout);
n=read(); m=read();
for(int i=1,x,y;i<=n;i++) x=read(),y=read(),add_edge(x,y);
for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);
for(int i=1;i<=n;i++) if(!jud[i]) se.insert(i);
while(se.size()) topo_sort();
for(int i=1;i<=n;i++) if(jud[i]&&!suc[i]) ans+=solve(i);
printf("%lld",ans);
return 0;
}

NOIP模拟59的更多相关文章

  1. Noip模拟59 2021.9.22

    新机房首模拟变倒数 T1 柱状图 关于每一个点可以做出两条斜率分别为$1,-1$的直线, 然后题意转化为移动最少的步数使得所有点都在某一个点的两条直线上 二分出直线的高度,判断条件是尽量让这条直线上部 ...

  2. 2021.9.22考试总结[NOIP模拟59]

    T1 柱状图 关于每个点可以作出两条斜率绝对值为\(1\)的直线. 将绝对值拆开,对在\(i\)左边的点\(j\),\(h_i-i=h_j-j\),右边则是把减号换成加号. 把每个点位置为横坐标,高度 ...

  3. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  4. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  5. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  6. NOIP模拟 1

    NOIP模拟1,到现在时间已经比较长了.. 那天是6.14,今天7.18了 //然鹅我看着最前边缺失的模拟1,还是终于忍不住把它补上,为了保持顺序2345重新发布了一遍.. #   用  户  名   ...

  7. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  8. NOIP 模拟4 T2

    本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...

  9. noip模拟32[好数学啊]

    noip模拟32 solutions 真是无语子,又没上100,无奈死了 虽然我每次都觉得题很难,但是还是有好多上100的 战神都200多了,好生气啊啊啊 从题开始变难之后,我的时间分配越来越不均匀, ...

  10. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

随机推荐

  1. jenkins 持续集成和交付 —— git hook(七)

    前言 这个hook的意思叫做钩子哈,前端听得多. 正文 好吧,这个git hook 有什么用呢? 前面说了一个轮询SCM这个东西呢,我是真的觉得这东西没啥用,经常扫描仓储算怎么回事呢? 但是如果主动通 ...

  2. JS isPrototypeOf 和hasOwnProperty 还有in的区别

    isPrototypeOf 和hasOwnProperty 的区别 isPrototypeOf 是判断原生链上是否有该对象. 1.isPrototypeOf isPrototypeOf是用来判断指定对 ...

  3. 力扣1668(java&python)-最大重复子字符串(简单)

    题目: 给你一个字符串 sequence ,如果字符串 word 连续重复 k 次形成的字符串是 sequence 的一个子字符串,那么单词 word 的 重复值为 k .单词 word 的 最大重复 ...

  4. Understand Abstraction and Interface

    Foreword 抽象和接口是Java中的两个关键字,也是两种最基本的优化软件项目手段.为什么说它们是一种优化项目的手段? 人分三六九等,不同等级的人,所接触的事和处理的事是不一样的.同理,项目也分大 ...

  5. 一个好的科技公司logo长这样!

    ​简介:一个好的科技logo能体现出行业独有的专业性和技术优势,让你的公司科技感加满! 近年来,越来越多的初创公司崭露头角,其中科技互联网公司的比重非常高.小云也收到很多朋友的留言,询问科技类公司应该 ...

  6. SaaS服务的私有化部署,这样做最高效|云效工程师指北

    ​简介:为了能够有效且高效地同时管理SaaS版本和私有化版本的发布过程,云效团队也结合云原生的基础设施和标准化工具(比如helm)进行了一系列的探索和实践,并将其中一些通能的能力进行了产品化.本文从问 ...

  7. SchedulerX 如何帮助用户解决分布式任务调度难题?

    ​简介:本文分别对任务调度平台的资源定义.可视化管控能力.分布式批处理能力进行了简述,并基于 SchedulerX 的能力结合实际业务场景提供了一些基础参考案例.希望通过上述内容能让大家方便地熟悉任务 ...

  8. 快手基于 Flink 构建实时数仓场景化实践

    简介: 一文了解快手基于 Flink 构建的实时数仓架构,以及一些难题的解决方案. 本文整理自快手数据技术专家李天朔在 5 月 22 日北京站 Flink Meetup 分享的议题<快手基于 F ...

  9. Spirng 当中 Bean的作用域

    Spirng 当中 Bean的作用域 @ 目录 Spirng 当中 Bean的作用域 每博一文案 1. Spring6 当中的 Bean的作用域 1.2 singleton 默认 1.3 protot ...

  10. ansible(9)--ansible的yum模块

    1. yum模块 功能:管理软件包,需要确认被管理端为红帽系列的,并且需要被管理端配置好yum源. 主要的参数如下: 参数 说明 name 指定安装软件包名或软件包URL state 指定yum对应的 ...