题目链接:

咕咕

闲扯:

哈哈这道T3考场上又敲了5个namespace,300+行,有了前车之鉴还对拍过,本以为子任务分稳了

结果只有30分哈哈,明明用极限数据对拍过不知怎么回事最后数据又是读不全,玄学,要是NOIP这样就GG了

首先第一个子任务贪心模拟即可,但是第二个子任务就像NOID1T1,你啥也不能输出但是我输出了0哈哈,真的是傻到家了,第三个子任务简单考虑一下即可;第四个子任务已经想到了偏正解的做法,但是用了个很SB的方法维护,昨天的T3也是这样但是都GG了...感觉退役钦定了

感谢WYT大佬正解讲解,高一神仙tql

分析:

先考虑第四个子任务,我说一下我在考场上的做法,我们设\(pos[i]\)是第i个任务的坐标,同时先将区间长度排序离线处理

先考虑pos[1]>0的情况,我们把相邻正负两点看成一对处理,所以我们可以一开始在负的点值那里加一个0点这样就凑成对了,考虑从一个负点右移到一个正点的时候,如果都不会出现不用右移的情况(也就是不会有直接覆盖正点的情况)答案就是上一次的总长度减去点个数乘以区间长度之差

但是如果出现了这种情况呢?首先我们离线处理是已经将区间长度从小到大排序,所以当前区间长度是这种情况下一个区间的长度肯定还会是这种情况。

所以遇到这种情况我们需要减去计算之前区间长度在这两点之间需要的移动距离,再将这两个踢出我们的考虑范围(我比较傻用了两个堆存储一个正点一个负点,由于是正值或负值是分别单调的只需要两个指针即可完成操作),同时点数减去2(成对考虑),再次计算贡献即可

pos[1]<0再分类讨论一下就好了

这种情况经过了对拍的检验应该是没什么问题的但是数据没读全也不知道咋回事

然后正解是怎么处理这个子任务的呢?我们可以把任务编号看成x轴,坐标位置看成y轴点出所有的点再将相邻两点连线是这个样子:

我们将相邻两点之间连线的长度叫做\(p[i]\),当前区间长度为\(L\),如果任意\(p[i]>L\)那么答案就是\(\sum (p[i]-L)\)

但是如果存在\(p[i]<=L\)呢,若\(a,b\)连线长度\(p<=L\),那么我们将这两点删去,将\(a-1,b+1\)之间连新的线

你会发现由于连线长度是单调的非常好处理,实际上我的做法也是在模拟类似的操作

再考虑没有第四个子任务的限制怎么做.首先我们可以预处理,对于一段连续的任务如果是单调的,那么我们只用保留头和尾就可以了,中间的显然不用管,那么这时候再仿照上面画出图像

会发现由于并没有任务4的限制预处理后还可能出现x这样的点,这时候连线长度就不是递增的了,怎么办呢?

我们把所有长度放入一个小根堆中,每次对于一个新区间长度L,如果堆顶长度p小于等于L,也就是说达到x-1时就已经覆盖了x,比如图中\(x-1\)到\(x\)这段折线,我们就把它相邻两段连线包括它本身换成另一条折线,这样显然是最优情况

所以我们还需要记录连线的前驱后继来个映射,还要用链表/map记录下对应位移序列之类的搞一搞,统计方案用上面一样的方法,不断更新连线段数和连线总长就好了

由于每段只会进堆一次,时间复杂度\(O(NlogN)\)

但是这道题细节巨坑...题解只说了在首尾要特判,但其实链表之类搞一搞真挺烦的,所以并没有写代码...

代码:

这是标程代码...我太懒了并没有自己写一份

#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const int maxn=1e5+10;
int n,m;
ll tot,ans[maxn];
vector<int> x;
vector<pair<int,int> > a;
map<int,int> mp; inline ll calc(ll k){
if(!mp.empty()&&mp.begin()->second<0)
return tot-(mp.size()-1)*k;
else
return tot-mp.size()*k;
}
inline void solve(){
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
int t=0;
for(int i=0;i<x.size();++i){
tot+=abs(x[i]);
mp[i]=x[i];
q.push(make_pair(abs(x[i]),i));
}
while(!q.empty()){
int id=q.top().second,tmp=q.top().first;q.pop();
map<int,int>::iterator p=mp.lower_bound(id);
if(p==mp.end()||p->first!=id||abs(p->second)!=tmp)
continue;
while(t<a.size()&&abs(p->second)>a[t].first)
ans[a[t].second]=calc(a[t].first),++t;
if(p!=mp.begin())
if(p!=prev(mp.end())){
tmp=p->second,tot-=abs(p->second);
tmp+=prev(p)->second,tot-=abs(prev(p)->second);
tmp+=next(p)->second,tot-=abs(next(p)->second);
mp.erase(prev(p));
mp.erase(next(p));
p->second=tmp,tot+=abs(tmp);
q.push(make_pair(abs(tmp),id));
}
else{
tot-=abs(p->second);
mp.erase(p);
}
else if(p->second>0)
if(p!=prev(mp.end())){
tmp=p->second,tot-=abs(p->second);
tmp+=next(p)->second,tot-=abs(next(p)->second);
mp.erase(next(p));
if(tmp){
p->second=tmp,tot+=abs(tmp);
q.push(make_pair(abs(tmp),id));
}
else
mp.erase(p);
}
else{
tot-=abs(p->second);
mp.erase(p);
}
}
while(t<a.size())
ans[a[t].second]=calc(a[t].first),++t;
} int main(){
freopen("z.in","r",stdin);
freopen("z.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=0,p,last=0;i<n;++i){
scanf("%d",&p);
if(p==last)
continue;
if(!x.empty()&&(x.back()<0&&p<last||x.back()>0&&p>last))
x.back()+=p-last;
else
x.push_back(p-last);
last=p;
}
for(int i=0,l;i<m;++i){
scanf("%d",&l);
a.push_back(make_pair(l,i));
}
sort(a.begin(),a.end());
solve();
for(int i=0;i<m;++i)
printf("%lld\n",ans[i]);
return 0;
}

[NOIP10.4模拟赛]3.z题解--思维的更多相关文章

  1. [NOIP10.6模拟赛]1.merchant题解--思维+二分

    题目链接: while(1)gugu(while(1)) 闲扯 考场上怕T2正解写挂其他两题没管只打了暴力,晚上发现这题思维挺妙的 同时想吐槽出题人似乎热衷卡常...我的巨大常数现在显露无疑QAQ 分 ...

  2. [NOIP10.5模拟赛]3.c题解--思维

    题目链接 这次不咕了 https://www.luogu.org/problemnew/show/AT2389 闲扯 考场20分爆搜走人 \cy 话说这几天T3都很考验思维啊 分析 我们先钦定一只鸡( ...

  3. [NOIP10.6模拟赛]2.equation题解--DFS序+线段树

    题目链接: 咕 闲扯: 终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ 首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解 然而考场上只得了86 ...

  4. [NOIP10.3模拟赛]3.w题解--神奇树形DP

    题目链接: 咕 闲扯: 这题考场上把子任务都敲满了,5个namespace,400行11k 结果爆0了哈哈,因为写了个假快读只能读入一位数,所以手测数据都过了,交上去全TLE了 把边分成三类:0. 需 ...

  5. [NOIP10.4模拟赛]2.y题解--折半搜索+状压计数

    题目链接: 咕 闲扯: 这题暴力分似乎挺多,但是一些奇奇怪怪的细节没注意RE了,还是太菜了 分析: 首先我们考虑最naiive的状压DP ,\(f[u][v][state]\)表示u开头,v结尾是否存 ...

  6. [NOIP10.5模拟赛]1.a题解--离散化+异或线段树

    题目链接: 咕咕咕 https://www.luogu.org/problemnew/show/CF817F 闲扯 在Yali经历几天折磨后信心摧残,T1数据结构裸题考场上连暴力都TM没打满 分析 观 ...

  7. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  8. 模拟赛 提米树 题解 (DP+思维)

    题意: 有一棵棵提米树,满足这样的性质: 每个点上长了一定数量的Temmie 薄片,薄片数量记为这个点的权值,这些点被标记为 1 到 n 的整数,其 中 1 号点是树的根,没有孩子的点是树上的叶子. ...

  9. DYOJ 【20220317模拟赛】瞬间移动 题解

    瞬间移动 题意 三维空间中从 \((0,0,0)\) 开始,每次移动 1,问刚好走 \(N\) 次能到 \((X,Y,Z)\) 的方案数 \(N\le10^7\),答案模 \(998244353\) ...

随机推荐

  1. mysqldump定时任务生成备份文件内容为空解决方法

    1问题:写好了一个mysqldump备份脚本(如图)直接执行可以正常生成备份文件,但在用crontab运行时却生成内容为空 2原因分析:由于mysqldump存在于全局环境变量mysql的bin下面, ...

  2. 用JS判断号码

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. [java]借助java.io.File类,完成文件批量改名

    列出某目录下的所有文件,将文件改名,借助java.io.File一个类就可以完成.大家可以发现,代码中的具体方法都是File一个类的. 另外要注意的是,File的全路径名,路径是一致的,父路径其实是文 ...

  4. 【python】详解事件驱动event实现

    [python]详解事件驱动event实现 所有的计算机程序都可以大致分为两类:脚本型(单次运行)和连续运行型(直到用户主动退出). 1.脚本型:脚本型的程序包括最早的批处理文件以及使用Python做 ...

  5. C++ STL swap_range

    #include <iostream>#include <vector>#include <deque>#include <algorithm> usi ...

  6. mac 终端杀进程

    killall 进程名 killall chromedriver 查看进程名的·方法:

  7. 查看oracle数据库的链接数和用户

    http://www.cnblogs.com/is1988/archive/2012/11/21/2780067.html 1.查询oracle的连接数select count(*) from v$s ...

  8. 【ARTS】01_23_左耳听风-201900415~2019004021

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  9. centos(linux)-jdk配置

    1.清理系统默认自带的jdk 在安装centos时,可能系统会默认安装了例如openjdk等,需要先手动卸载 先执行:rpm -qa | grep jdk (查看已经自带的jdk): 卸载命名:sud ...

  10. 使用C++11原子量实现自旋锁

    一.自旋锁 自旋锁是一种基础的同步原语,用于保障对共享数据的互斥访问.与互斥锁的相比,在获取锁失败的时候不会使得线程阻塞而是一直自旋尝试获取锁.当线程等待自旋锁的时候,CPU不能做其他事情,而是一直处 ...