noip模拟31 solutions

我就觉得这些考试题是越考越难,我是也越考越完蛋,已经完完全全的接近爆零了

只有20pts,说真的这还是我第一次挂掉30pts,本来我还有50pts嘞

所以这次考试我直接炸裂,改题的时候也不是非常的顺利,一直不知道该咋办

但是我得到了一个经验,线段树真的是个好东西,得好好的利用

T1 game

这个题真的快要气死我了,我在考场上一秒切掉最优解

一个小时没想出来字典序,真是无奈。。。。。

最后看题解的时候发现这个直接线段树维护就好了

维护啥呢?维护这个区间内所有的a,b一共可以造成的贡献是多少

每次二分这个不影响贡献的边界值,可能不太好理解

就是你发现在两个序列中,只要b大于a就好了,所以我们在权值线段树中在相应的位置的相应的序列中插入1

这样我们每次pushup的时候就可以维护出每个区间的贡献

我们按顺序便利a数组,首先删掉当前的a,去线段树中寻找不影响总贡献的最大值

这个肯定是单调的,因为你区间内的数越多,获得贡献的可能性越大

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
int n,a[N],b[N];
struct XDS{
#define ls x<<1
#define rs x<<1|1
int sum[N*4],dw[N*4],up[N*4];
void pushup(int x){
int tmp=min(dw[ls],up[rs]);
sum[x]=sum[ls]+sum[rs]+tmp;
dw[x]=dw[ls]+dw[rs]-tmp;
up[x]=up[ls]+up[rs]-tmp;
return ;
}
void ins(int x,int l,int r,int pos,int v1,int v2){
//cout<<x<<" "<<l<<" "<<r<<" "<<pos<<endl;
if(l==r){
dw[x]+=v1;
up[x]+=v2;
return ;
}
int mid=l+r>>1;
if(pos<=mid)ins(ls,l,mid,pos,v1,v2);
else ins(rs,mid+1,r,pos,v1,v2);
pushup(x);return ;
}
#undef ls
#undef rs
}xds;
int mx,sum;
multiset<int> st;
signed main(){
scanf("%d",&n);
for(re i=1;i<=n;i++)scanf("%d",&a[i]),mx=max(mx,a[i]);
for(re i=1;i<=n;i++)scanf("%d",&b[i]),mx=max(mx,b[i]);
//cout<<mx<<endl;
for(re i=1;i<=n;i++)xds.ins(1,1,mx,a[i],1,0);
for(re i=1;i<=n;i++)xds.ins(1,1,mx,b[i],0,1),st.insert(b[i]);
int sum=xds.sum[1];
for(re i=1;i<=n;i++){
//cout<<i<<endl;
xds.ins(1,1,mx,a[i],-1,0);
int l=a[i]+1,r=*st.rbegin(),mid;
//cout<<l<<" "<<r<<" ";
while(l<r){
//cout<<l<<" "<<r<<endl;
mid=l+r+1>>1;
xds.ins(1,1,mx,mid,0,-1);
if(1+xds.sum[1]==sum)l=mid;
else r=mid-1;
xds.ins(1,1,mx,mid,0,1);
}
//cout<<i<<" sb"<<" ";
xds.ins(1,1,mx,l,0,-1);
if(l<=r&&1+xds.sum[1]==sum){
printf("%d ",l);
sum--;
st.erase(st.find(l));
}
else{
xds.ins(1,1,mx,l,0,1);
l=1;r=a[i];
while(l<r){
//cout<<l<<" "<<r<<endl;
mid=l+r+1>>1;
xds.ins(1,1,mx,mid,0,-1);
if(xds.sum[1]==sum)l=mid;
else r=mid-1;
xds.ins(1,1,mx,mid,0,1);
}
xds.ins(1,1,mx,l,0,-1);
printf("%d ",l);
st.erase(st.find(l));
}
//cout<<endl;
}
}


T2 time

这个考场上其实就差一步就好了,逆序对没用对

所以这个题就爆掉了30pts

那这个题的正解也是线段树(其实我是看着std的双端队列不爽才写线段树的)

最小值一定在两端,所以每次只需要将这个最小值向左右两边移动就好了

你发现这个最小值的移动并不会对比他大的值造成任何影响

我们只需要用线段树维护左边的最小值以及距离,右边一样

因为这里会出现相同的数字,所以左右两边要分别维护

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int n,a[N],ans;
struct XDS{
#define ls x<<1
#define rs x<<1|1
int lmn[N*4],lrk[N*4],rmn[N*4],rrk[N*4];
int siz[N*4];
void pushup(int x){
if(a[lmn[ls]]<=a[lmn[rs]]){
lmn[x]=lmn[ls];
lrk[x]=lrk[ls];
}
else{
lmn[x]=lmn[rs];
lrk[x]=lrk[rs]+siz[ls];
}
if(a[rmn[rs]]<=a[rmn[ls]]){
rmn[x]=rmn[rs];
rrk[x]=rrk[rs];
}
else{
rmn[x]=rmn[ls];
rrk[x]=rrk[ls]+siz[rs];
}
siz[x]=siz[ls]+siz[rs];
return ;
}
void build(int x,int l,int r){
if(l==r){
lmn[x]=rmn[x]=l;
lrk[x]=rrk[x]=1;
siz[x]=1;
return ;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(x);return ;
}
void del(int x,int l,int r,int pos){
//cout<<x<<" "<<l<<" "<<r<<" "<<pos<<endl;
if(l==r){
lmn[x]=rmn[x]=0;
lrk[x]=rrk[x]=inf;
siz[x]=0;
return ;
}
int mid=l+r>>1;
if(pos<=mid)del(ls,l,mid,pos);
else del(rs,mid+1,r,pos);
pushup(x);return ;
}
#undef ls
#undef rs
}xds;
signed main(){
scanf("%d",&n);
a[0]=inf;
for(re i=1;i<=n;i++)
scanf("%d",&a[i]);
xds.build(1,1,n);
for(re i=1;i<=n;i++){
//cout<<i<<" "<<xds.lmn[1]<<" "<<xds.rmn[1]<<endl;
if(xds.lrk[1]<=xds.rrk[1]){
ans+=xds.lrk[1]-1;
xds.del(1,1,n,xds.lmn[1]);
}
else{
ans+=xds.rrk[1]-1;
xds.del(1,1,n,xds.rmn[1]);
}
//cout<<"sB"<<endl;
}
printf("%d",ans);
}


T3 cover

这个最简单了,看到包含和不相交,一眼就是树形dp

可是我不会打,考完了直接一个\(\mathcal{O(n^2)}\)的暴力转移拿到45

这个差分的确是个好东西;

直接把每一个权值插入到对应的节点的multiset中

我们每次让轻链合并到重链,因为一颗树上的轻链包含的节点总个数就是n

所以合并的总复杂度是\(\mathcal{O(nlogn)}\)

这个差分其实就是对一个函数进行做差,

我们将这个二维的转移数组,每个节点当作一个函数,那么他的差分一定是单调不增的

为啥,因为最大的放在前面一定最优

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=3e5+5;
int n,m;
struct node{
int l,r;
ll a;
node(){}
bool operator < (node x)const{
if(l!=x.l)return l<x.l;
return r>x.r;
}
}sca[N];
int to[N],nxt[N],head[N],rp;
int du[N];
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
int sta[N],tot;
bool check(int x,int y){
return sca[x].l<=sca[y].l&&sca[y].r<=sca[x].r;
}
multiset<ll> f[N];
void merge(multiset<ll> &x,multiset<ll> &y){
if(x.size()<y.size())swap(x,y);
vector<ll> tmp;tmp.clear();
multiset<ll>::iterator it=y.begin();
while(it!=y.end()){
//cout<<"sb"<<endl;
tmp.push_back(*it+*x.begin());
x.erase(x.begin());
it=next(it);
}
for(re i=0;i<tmp.size();i++)x.insert(tmp[i]);
}
void dfs(int x){
for(re i=head[x];i;i=nxt[i]){
int y=to[i];dfs(y);
merge(f[x],f[y]);
//cout<<x<<" "<<y<<" "<<"ok"<<endl;
}
if(x==m+1)return ;
f[x].insert(-sca[x].a);
}
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=m;i++)scanf("%d%d%lld",&sca[i].l,&sca[i].r,&sca[i].a);
sort(sca+1,sca+m+1);
sta[tot=1]=m+1;
for(re i=1;i<=m;i++){
while(tot>1&&!check(sta[tot],i)){
add_edg(sta[tot-1],sta[tot]);
du[sta[tot]]++;tot--;
}
sta[++tot]=i;
}
tot--;
while(tot){
add_edg(sta[tot],sta[tot+1]);
du[sta[tot+1]]++;tot--;
}
dfs(m+1);
//cout<<"sb"<<endl;
ll ans=0;
//cout<<"sb"<<" "<<(*f[m+1].begin())<<endl;
for(re i=1;i<=m;i++){
//cout<<i<<" ";
if(f[m+1].size()){
ans+=-(*f[m+1].begin());
f[m+1].erase(f[m+1].begin());
}
printf("%lld ",ans);
}
}


noip模拟31[time·game·cover]的更多相关文章

  1. NOIP 模拟 $31\; \rm Cover$

    题解 \(by\;zj\varphi\) 因为对于所有区间,都只有包含和被包含关系,这就是一个树形结构. 设 \(\rm f_{i,j}\) 表示在第 \(\rm i\) 个节点,最多被覆盖 \(\r ...

  2. Noip模拟31 2021.8.5

    T1 Game 当时先胡了一发$\textit{Next Permutation}$... 然后想正解,只想到贪心能求最大得分,然后就不会了.. 然后就甩个二十分的走了... 正解的最大得分(叫它$k ...

  3. 2021.8.5考试总结[NOIP模拟31]

    暴力打满直接rk3? T1 Game 想了一万种贪心和两万种$hack$. 可以先用最显然的贪心求出最高得分是多少.(从小到大用最小的大于$b_i$的$a$得分) 然后用一棵权值线段树维护值域内$a$ ...

  4. noip模拟31

    \(\color{white}{\mathbb{峭壁通天,横崖无岸,惊无识之马,断无疆之虹,名之以:悬崖}}\) 一看完题就暴肝 \(t1\),胡了两个贪心,实现了一个,发现都是错的,然后奖金两个小时 ...

  5. NOIP模拟 31

    补坑 skyh又AK 赛时榜搜索我的姓: 下一条 ... 自闭了. (只是表达对B哥强烈的崇敬) (如果B哥介意我把名字贴出来请联系我删掉) T1一打眼,好像就一个gcd 康了眼大样例,觉得没啥问题 ...

  6. NOIP 模拟 $31\; \rm Time$

    题解 \(by\;zj\varphi\) 考虑如何才能最优. 每次一定把当前最小值移动到边界上,那么看它向左还是向右移更优. 用树状数组维护一下即可,复杂度 \(\mathcal O\rm (nlog ...

  7. NOIP 模拟 $31\; \rm Game$

    题解 很容易求出在没有字典序最大的限制条件下的最多胜利场数. 这样就可以对于每一位放最优的解,怎么做,二分答案. 分两种情况,一种是当前一位是输的,一种是赢的,复杂度 \(\mathcal O(\rm ...

  8. 「题解」NOIP模拟测试题解乱写I(29-31)

    NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...

  9. noip模拟33

    \(\color{white}{\mathbb{失足而坠千里,翻覆而没百足,名之以:深渊}}\) 这场考试的时间分配非常不科学 开题试图想 \(t1\) 正解,一个半小时后还是只有暴力,特别惊慌失措 ...

随机推荐

  1. etcd 添加用户,授权特定目录

    适用场景 多组共用etcd集群,创建一个新用户.新目录,让这个新用户只有新目录的使用权限. 命令和顺序 创建目录,注意此处是v2 curl -u root:pwd http://host:2379/v ...

  2. 『心善渊』Selenium3.0基础 — 16、Selenium对iframe表单的操作

    目录 1.什么是iframe表单 2.iframe表单操作流程 3.iframe表单操作常用方法 (1)进入表单 (2)多表单切换 4.表单操作示例 1.什么是iframe表单 实际上就是HTML页面 ...

  3. Keyboarding(信息学奥赛一本通-T1452)

    [题目描述] 出自 World Final 2015 F. Keyboarding 给定一个 r 行 c 列的在电视上的"虚拟键盘",通过「上,下,左,右,选择」共 5 个控制键, ...

  4. FastApi持续更新

    ​ FastAPI 框架,高性能,易于学习,高效编码,生产可用 官方文档: https://fastapi.tiangolo.com FastAPI 是一个用于构建 API 的现代.快速(高性能)的 ...

  5. 流程自动化RPA,Power Automate Desktop系列 - 构建VuePress文档中心脚手架

    一.背景 笔者曾基于VuePress搭建过一个文档中心,但是在实现在线管理功能之前,很多时候,新建文档需要手动处理很多数据,看有没有可能实现一个脚手架来处理这些问题,所谓脚手架,就是进行文档初始化的一 ...

  6. 流程自动化RPA,Power Automate Desktop系列 - 发布文档中心

    一.背景 内网中有一个基于VuePress搭建的静态文档中心,但是每次修改后都需要重新Build一次才行,之前都是手动执行命令,现在可以基于Power Automate Desktop来创建任务了. ...

  7. 六QT使用mqtt

    QT官方的mqtt是qmqtt,头文件是 #include <qmqttclient.h> 官方的文档地址 https://doc.qt.io/QtMQTT/qmqttclient.htm ...

  8. 利用C语言判别用户输入数的奇偶性和正负性

    要求:利用C语言判别用户输入数的奇偶性和正负性 提示:可以利用%求余数来判别 由题可知 我们需要if..else的结构来实现区分奇偶和正负 区分奇偶我们可以用: if (a % 2 == 0) { p ...

  9. 利用C语言将混乱数字排序(即冒泡排序法)(含思路)

    大一C语言 你没学过吗 这篇可以称的上入门级别的c语言了 当然还有水仙花数,冒泡排序等经典的C语言程序 后面也会逐一更新 尽情期待喔~~~ 冒泡排序法的基本思路为:每次将相邻的两个数比较,将小的调在前 ...

  10. AcWing 102. 最佳牛围栏

    农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头. 约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大 ...