终于有时间写博客了,前面一直咕咕咕都快变成一只公鸡了......这次考试,真的很意外,我在考场上觉得自己打出了T1的正解,样例一拍就过,还跑得嘎嘎快,然后T2,T3码了两个暴力,觉得自己应该能100pts+,结果竟然....爆蛋了,T1思路出现了问题,T2打假了,T3TLE飞起,但是收获还是有的,以后注意多加思考,看看自己的思路有没有正确性,还有,一定要用暴力程序进行验证(暴力不要打假...),样例真是太水了....

T1 Game

思路:最大得分可以利用线段树很容易求出,如果没有字典序最大的限制,那么这道题就非常简单,但这只是如果,现在这道题有了双重限制,听某巨佬的叙述,得知一般有双重限制的题一般有两种思考方向,一种是二分,另一种是主席树,那么很显然,这道题我们可以考虑二分的思想,具体来说就是我们先通过线段树求出最大得分,然后考虑这样一件事情,如果有一对点可以对答案造成贡献,那么我们将他们同时删去必然会使更新后的最大得分-1,这样我们就可以进行二分查找了,对于可以造成贡献的点,我们二分出他可以对应的最大的另外一个点,具体实现见代码:

AC_code



#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
#define lc (rt<<1)
#define rc (rt<<1|1)
using namespace std;
const int N=200010;
const int INF=1e9+10;
int n;
int a[N],b[N];
multiset<int> sm;
ii read()
{
int x=0;
bool f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=0;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
struct Segment_Tree
{
int A[N<<2],B[N<<2],sum[N<<2];
iv pp(int rt)
{
int u=min(A[lc],B[rc]);
sum[rt]=sum[lc]+sum[rc]+u;
A[rt]=A[lc]+A[rc]-u;
B[rt]=B[lc]+B[rc]-u;
}
iv insert(int rt,int l,int r,int p,int x,int y)
{
if(l==r)
{
A[rt]+=x;
B[rt]+=y;
return;
}
int mid=(l+r)>>1;
if(mid>=p)
insert(lc,l,mid,p,x,y);
else
insert(rc,mid+1,r,p,x,y);
pp(rt);
}
}T;
int main()
{
const int N=100000;
n=read();
for(re i=1;i<=n;i++)
{
a[i]=read();
T.insert(1,1,N,a[i],1,0);
}
for(re i=1;i<=n;i++)
{
b[i]=read();
T.insert(1,1,N,b[i],0,1);
sm.insert(b[i]);
}
int ans=T.sum[1];
for(re i=1;i<=n;i++)
{
int l=a[i]+1,r=*(--sm.end()),out=-1;
T.insert(1,1,N,a[i],-1,0);
while(l<=r)
{
int mid=(l+r)>>1;
T.insert(1,1,N,mid,0,-1);
if(T.sum[1]+1==ans)
{
l=mid+1;
out=mid;
}
else
r=mid-1;
T.insert(1,1,N,mid,0,1);
}
if(out!=-1)
{
--ans;
sm.erase(sm.find(out));
T.insert(1,1,N,out,0,-1);
printf("%d ",out);
}
else {
l=1,r=a[i],out;
while(l<=r)
{
int mid=(l+r)>>1;
T.insert(1,1,N,mid,0,-1);
if(T.sum[1]==ans)
{
l=mid+1;
out=mid;
}
else
r=mid-1;
T.insert(1,1,N,mid,0,1);
}
printf("%d ",out);
sm.erase(sm.find(out));
T.insert(1,1,N,out,0,-1);
}
}
return 0;
}


T2 Time

这道题,或者说是这一种对数列进行排列的题,我是比较不自信的,因为自己不怎么有思路,导致我没有留出时间进行思考,这也是一个教训,逃避不是永久的办法,只有自己敢去想,去做,才能解决问题。

思路:这道题要求小的数字往两边靠,那很显然,如果要做到最小操作次数就要比较向左还是向右移动更优,可以利用线段树或者树状数组实现,算法的正确性在于,当我们将小数字向边缘移动的时候,我们都会将比他大的数字向中心移动,所以我们只需要利用贪心的思想只考虑使当前最优即可。

AC_code


#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
#define lc (rt<<1)
#define rc (rt<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int N=1e5+10;
const int INF=1e9+10;
int n;
deque<int>q[N];
ii read()
{
int x=0;
bool f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=0;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
struct Segment_Tree
{
int sum[N<<2];
iv pp(int rt)
{
sum[rt]=sum[lc]+sum[rc];
}
iv insert(int rt,int l,int r,int p,int z)
{
if(l==r)
{
sum[rt]+=z;
return;
}
if(mid>=p)
insert(lc,l,mid,p,z);
else
insert(rc,mid+1,r,p,z);
pp(rt);
}
ii query(int rt,int l,int r,int L,int R)
{
if(L>R)
return 0;
if(L<=l&&r<=R)
return sum[rt];
if(mid>=R)
return query(lc,l,mid,L,R);
if(mid<L)
return query(rc,mid+1,r,L,R);
return query(lc,l,mid,L,R)+query(rc,mid+1,r,L,R);
}
}T;
int main()
{
int ans=0;
n=read();
for(re i=1;i<=n;i++)
{
q[read()].push_back(i);
T.insert(1,1,n,i,1);
}
for(re i=1;i<=n;i++)
{
while(!q[i].empty())
{
int l=q[i].front(),r=q[i].back();
int sl=T.query(1,1,n,1,l-1),sr=T.query(1,1,n,1,n)-T.query(1,1,n,1,r);
if(sl<=sr)
{
ans+=sl;
T.insert(1,1,n,l,-1);
q[i].pop_front();
}
else
{
ans+=sr;
T.insert(1,1,n,r,-1);
q[i].pop_back();
}
}
}
printf("%d\n",ans);
return 0;
}


T3 Cover

好吧,这道题怪我没有认真听课,区间两两之间只有包含和不相交的关系满足这个条件,他们的包含关系一定会构成一颗树,那么这道题显然就是一个树形DP(而不是我写的区间DP),记 \(f_{i,j}\)表示在 i 为根的子树中点被覆盖的最多次数为 j 的最优答案,转移

的时候首先将所有子树的答案直接合并,然后考虑点 i 的贡献 \(f_{i,j}=max(f_{i,j},f_{i,j-1}+val)\) , 这样朴素的DP方程显然时间复杂度会爆炸,考虑优化,我们考虑答案更新的过程,我们利用包含关系构建一颗树,那么我们将子树合并的时候,当前的节点会存储多个val,包括自己本身的,还有自己的儿子合并得到的,这种答案属于同一层,我们需要不同层之间的转移。也就是到达跟节点的时候我们需要不断从左右区间中分别拿出最大值,这就是我们需要的答案,那么我们就可以利用一个 set ,通过一个合并的操作插入值并排序,具体实现见代码:

AC_code



#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
#define lc (rt<<1)
#define rc (rt<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int N=1e5+10;
const int INF=1e9+10;
int n;
deque<int>q[N];
ii read()
{
int x=0;
bool f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=0;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
struct Segment_Tree
{
int sum[N<<2];
iv pp(int rt)
{
sum[rt]=sum[lc]+sum[rc];
}
iv insert(int rt,int l,int r,int p,int z)
{
if(l==r)
{
sum[rt]+=z;
return;
}
if(mid>=p)
insert(lc,l,mid,p,z);
else
insert(rc,mid+1,r,p,z);
pp(rt);
}
ii query(int rt,int l,int r,int L,int R)
{
if(L>R)
return 0;
if(L<=l&&r<=R)
return sum[rt];
if(mid>=R)
return query(lc,l,mid,L,R);
if(mid<L)
return query(rc,mid+1,r,L,R);
return query(lc,l,mid,L,R)+query(rc,mid+1,r,L,R);
}
}T;
int main()
{
int ans=0;
n=read();
for(re i=1;i<=n;i++)
{
q[read()].push_back(i);
T.insert(1,1,n,i,1);
}
for(re i=1;i<=n;i++)
{
while(!q[i].empty())
{
int l=q[i].front(),r=q[i].back();
int sl=T.query(1,1,n,1,l-1),sr=T.query(1,1,n,1,n)-T.query(1,1,n,1,r);
if(sl<=sr)
{
ans+=sl;
T.insert(1,1,n,l,-1);
q[i].pop_front();
}
else
{
ans+=sr;
T.insert(1,1,n,r,-1);
q[i].pop_back();
}
}
}
printf("%d\n",ans);
return 0;
}


noip模拟测试31的更多相关文章

  1. [NOIP模拟测试31]题解

    A.math 考场乱搞拿了95,2333. 考虑裴蜀定理:$ax+by=z$存在整数解,当且仅当$gcd(a,b)|z$. 那么如果某个数能够被拼出来,就必须满足所有$a_i$的$gcd$是它的因子. ...

  2. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  3. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  4. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  5. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

  6. NOIP模拟测试17&18

    NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...

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

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

  8. NOIP模拟测试1(2017081501)

    好,今天是cgg第一次举行模拟测试,希望各位支持. 时间限制:2小时 题目链接: 题目一:水得都没名字了 题目二:车站 题目三:选数 不要觉得2小时太少,我的题目很良心,都很简单. 答案可以在模拟测试 ...

  9. 2019.8.14 NOIP模拟测试21 反思总结

    模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...

随机推荐

  1. zookeeper集群及kafka集群搭建

    1.zookeeper集群搭建 1.1 上传安装包 官网推荐至少3个节点,我们这里也用三个节点192.169.2.18  192.169.1.82  192.169.1.95 准备好安装包,zooke ...

  2. .Net Core:限流

    一.环境 1.vs2019 2..Net Core 3.1 3.引用 AspNetCoreRateLimit 4.0.1 二.基础使用 1.设置 在Startup文件中配置如下,把配置项都放在前面: ...

  3. 如何优雅地实现浏览器兼容与CSS规则回退

    读完了<Visual Studio Code权威指南>,前端方面书籍不能停,于是捡起「CSS一姐」 Lea Verou 的<CSS魔法>. 我们没法控制用户使用新版本还是老版本 ...

  4. HDU 1686 Oulipo kmp裸题

    kmp算法可参考 kmp算法 汇总 #include <bits/stdc++.h> using namespace std; const int maxn=1000000+5; cons ...

  5. POJ 2084 Game of Connections 卡特兰数

    看了下大牛们的,原来这题是卡特兰数,顺便练练java.递归式子:h(0)=1,h(1)=1   h(n)= h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) ( ...

  6. 计算机、程序和java简介

    内存 计算机的内存是由一个有序的字节序列组成,用于存储程序及程序需要的数据.你可以将内存想象成计算机执行程序的工作区域.一个程序和它的数据在被CPU执行前必须移到计算机的内存中. 每个字节都是有一个唯 ...

  7. CentOS-yum安装Redis(单点)

    源文件安装(推荐安装) 在CentOS系统中,首先安装EPEL仓库,然后更新yum源: $ yum install epel-release -y $ yum update -y 然后安装Redis数 ...

  8. 想成为Java高手的25个学习目标

    本文将告诉你学习Java需要达到的25个目标,希望能够对你的学习及找工作有所帮助.对比一下自己,你已经掌握了这25条中的多少条了呢? 1.你需要精通面向对象分析与设计(OOA/OOD).涉及模式(GO ...

  9. Hibernate框架(一)总结介绍

    作为SSH三大框架之一的Hibernate,是用来把程序的Dao层和数据库打交道用的,它封装了JDBC的步骤,是我们对数据库的操作更加简单,更加快捷.利用Hibernate框架我们就可以不再编写重复的 ...

  10. 大数据-Hadoop虚拟机的准备以及配置(三台机子)

    虚拟机的准备 修改静态IP(克隆的虚拟机) vim /etc/udev/rules.d/70-persistent-net.rules 配置网络: Vim /etc/sysconfig/network ...