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. WPF随笔收录-实时绘制心率曲线

    一.前言 在自己的项目中,涉及到实时心率曲线的绘制,项目上的曲线绘制,一般很难找到能直接用的第三方库,而且有些还是定制化的功能,所以还是自己绘制比较方便.很多人一听到自己画就害怕,感觉很难,今天就分享 ...

  2. TypeScript 中泛型的理解?应用场景?

    一.是什么 泛型程序设计(generic programming)是程序设计语言的一种风格或范式 泛型允许我们在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型 ...

  3. cookie与localStorage与sessionStorage

    1. cookie 1_1: 简述 HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送(由服务器设置后返回给浏览器端)到用户浏览器并保存在本地的一小块数据.浏览器 ...

  4. Flink 1.13,面向流批一体的运行时与 DataStream API 优化

    简介: 在 1.13 中,针对流批一体的目标,Flink 优化了大规模作业调度以及批执行模式下网络 Shuffle 的性能,以及在 DataStream API 方面完善有限流作业的退出语义. 本文由 ...

  5. [PHP] 浅谈 Laravel auth:api 不同驱动 token 和 passport 的区别

    token 驱动使用 TokenGuard 用传递的值去用户表中查询 member_token 字段的值,看是否有匹配的. 服务端需要在用户表 member_token 字段中存储 access_to ...

  6. dotnet C# 根据椭圆长度和宽度和旋转角计算出椭圆中心点的方法

    本文来告诉大家如何根据椭圆长度和宽度和旋转角计算出椭圆中心点的方法 方法很简单,请看代码 /// <summary> /// 辅助进行椭圆点计算的类 /// </summary> ...

  7. 国产 Web 组态软件 TopStack V5.0 发布

    简介 TopStack 是一款轻量型 Web 组态软件,提供设备数据采集.定时任务.控制策略.联动控制.设备告警.设备维护管理.设备绩效管理.能源管理.组态开发.报表开发等核心功能.支持移动端访问,支 ...

  8. Unity 热更--AssetBundle学习笔记 1.0【AB包资源加载工具类的实现】

    工具类封装 通过上文中对AB包加载API的了解和简单使用,对AB包资源加载的几种方法进行封装,将其写入单例类中,如代码展示. 确保每个AB资源包只加载一次: 在LoadAssetBundleManag ...

  9. 一些简单的Post方式WebApi接收参数和传递参数的方法及总结

    原文地址:https://www.zhaimaojun.top/Note/5475297(我自己的博客网站) 各种Post方式上传参数到服务器,服务器接收各种参数的示例 webapi可以说是很常用了, ...

  10. rails角本启动和停止

    start.sh #!/bin/bash nohup rails s Puma -d >> run_log.log 2>&1 & stop.sh #!/bin/bas ...