【赛时总结】NOIP2018-三校联考1024
◇NOIP三校联考-1024◇
发现以前的博客写得似乎都很水……基本上都没什么阅读量QwQ 决定改过自新╰( ̄ω ̄o) 就从这篇博客开始吧~
现场考得无地自容,看到题解才发现一些东西……(我第三题还没有做出来,反正做出来再补上)
◊ 题目& 简单解析
第一题:组合
【题目】
有n条线段,线段的两端点各有一个值(线段两端值可以相同,也可以存在端点值相同的多条线段)。如果线段A的端点的值为(a,b),线段B的端点的值为(b,c),则可以通过将A,B相接,使AB构成一条端点值为(a,c)的线段。求是否存在一种按顺序连接线段的方案,使得所有线段连成一条线段。
另外给出一个参数T,如果T=1,则可以将线段调转方向,即线段 (a,b) 可以看成 (b,a);如果T=2,则线段不能调转方向。
输入:第一行给出T和n,m,n表示线段端点的值∈[1,n],m表示共有m条线段;接下来m行每行描述一条线段(a[i],b[i])
输出:第一行输出"YES"/"NO"表示是否存在方案;若为"YES"输出任意一组方案(按连接顺序输出线段编号,若线段连接时调转方向,则输出其编号的相反数)。
【分析】
由于每条线段只能使用一次且必须使用,但是端点值可以重复多次,若将线段(a,b)看作连接a,b的边,则问题转变为求一条欧拉路径(不一定是欧拉环),而T描述的是边是有向边还是无向边(可调转方向则是无向边)。根据欧拉路径的性质——若为无向图,则度数为奇数的点的个数不能超过2,如果存在度数为奇数的点,则必须以某一个度数为奇数的点作为欧拉路径;若为有向图,则出度不等于入度的点的个数不能超过2,且如果存在入度大于出度的点,则必须以该点作为欧拉路径的起点。
根据上述特征先建图。然后判断点的度数,同时确定起点(如果无法找到起点,即上述的两种特殊情况都不存在,则形成的是欧拉回路,所以可以将任意一点作为起点(注意不要直接把1作为起点,因为数据并没有保证点1~n都出现过) 本地检测的时候SpecialJudge写得丑,然后检测器碰到这种情况自己炸了(lll¬ω¬))。然后就用到了我考试过后才学的Hierholzer算法,专门拿来求欧拉路径/欧拉回路——如果图上存在欧拉回路,则求得的就是欧拉回路,否则求得的是欧拉路径。
Hierholzer算法大概就是从欧拉路径的起点出发,DFS选择一条没有走过的边继续走,直到不能走(没有边或者边都走过)为止,当DFS回溯时,将该边入栈。最后将栈内的所有边出栈就可以得到一条欧拉路径。
当然这样求到的是图中最大的一条欧拉路径,如果欧拉路径的边数没有达到m,即没有走过图中所有的边,则输出"NO";比如 (↔表示连接)"1↔2,2↔1,3↔4,4↔3"显然无法走完整个图。
第二题:统计
【题目】
给出一个长度为n的序列a[i],对序列进行m次操作,每次操作指定一个下标i∈(1,n),对于每一个j | j≥i且a[j]≤a[i] ,将a[j]从原数组中提出(原数组中a[j]的位置留空),再对所有满足条件的a[j]单独排序,最后按顺序放入原数组的空位中。问在操作前和进行操作后数组中逆序对的数量。
eg: a = {1,3,4,2,6,1} → (i=2) → a[j] = {3(a[2]),2(a[4]),1(a[6])} → 排序 → a[j]={1,2,3} → 放入空位 → a = {1,1,4,2,6,3}
【分析】
众所周知,求逆序对除了用归并排序,还可以用树状数组。根据树状数组,我们可以求出f[i],表示在i后面的小于a[i]的数的个数(即倒序从n到1插入a[i],再询问小于a[i]的数的个数)。设操作中被选中的元素的下标集合为 pos(pos升序排列),则对于 j∈pos ,以a[j]作为较大值的逆序对仅存在 ( a[j] , a[k]|k∈pos且k>j ) ,应该很好理解吧,就不多做解释了。因此在对a[j]排序后,对于每一个 i∈pos,就不存在以a[i]为较大值的逆序对了。因此它对答案的贡献就减少了f[i],但是它的改变不会对以其他元素为较大值的逆序对的数量产生影响。
为什么不产生影响?做一个简单的解释:假设选中a[j]的j的最小值为L。
①对于L之前的数a[i],a[j]排序后仍然在a[i]的后面,且a[i]与a[j]的相对大小没有改变,因此数量不会改变;
②对于L~n之间的数a[i],满足 a[i]>a[j](操作的要求),虽然排序后a[j]的位置改变,但是仍然小于a[i],且数目不变,因此数量不会改变;
举个例子:
好了,扯到贡献了。那么就相当于每次操作后,被操作的a[j]对逆序对的贡献(以a[j]为较大值的逆序对的数量)就变为0了。可以看成把a[j]删除,但是只是删去a[j]的贡献,而在统计其他数的逆序对的时候需要统计a[j]。记最初序列中逆序对的数量为sum,那么我们每进行一次操作,就需要执行 sum-=f[j](减去a[j]的贡献),顺便删除a[j]。
删除?双向链表!从选中的下标i出发,按链表顺序遍历j,如果a[j]<=a[i],则将j的前驱接上j的后继(删除),将sum-=f[j],给f[j]赋值为0。感觉是正解对吧 QwQ?然后就发现被某chuichui tly加的一组特殊数据卡掉了……%%%
无奈写正解,好吧,其实是线段树!用线段树维护区间最小值——如果区间[i,n]的最小值都大于a[i]的话,那么这个区间就不需要操作,否则查找子区间,直到找到叶节点,就找到了小于等于a[i]的a[j],然后将a[j]改为INF,sum-=f[j]。这样虽然和链表的思路是一样的……但是时间复杂度就由 O(n) 变成了 O(log n)!挺优秀的……(●'◡'●)
(第三题还没做出来,太弱了……好了好了,粘代码了)
◊ 源代码
【第一题-merge】
/*Lucky_Glass*/
#include<bits/stdc++.h>
using namespace std;
const int N=int(2e5),M=int(1e5);
int tag,m,n,beg,cnt;
int tot[M+5],ans[N+5];
bool vis[N+5];
struct LINK{int v,id;};
vector< LINK > lnk[M+5];
void DFS(int u,int id){
for(int i=0;i<(int)lnk[u].size();i++)
if(!vis[abs(lnk[u][i].id)]){
vis[abs(lnk[u][i].id)]=true;
DFS(lnk[u][i].v,lnk[u][i].id);
}
if(id) ans[++ans[0]]=id;
}
int main(){
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
scanf("%d%d%d",&tag,&m,&n);
if(tag==1){
for(int i=1;i<=n;i++){
int u,v;scanf("%d%d",&u,&v);beg=u;
tot[u]^=1;tot[v]^=1;
lnk[u].push_back((LINK){v,i});
lnk[v].push_back((LINK){u,-i});
}
for(int i=1;i<=m;i++)
if(tot[i])
cnt++,beg=i;
if(cnt>2)
printf("NO\n"),exit(0);
DFS(beg,0);
}
else{
for(int i=1;i<=n;i++){
int u,v;scanf("%d%d",&u,&v);beg=v;
lnk[u].push_back((LINK){v,i});
tot[u]++;tot[v]--;
}
for(int i=1;i<=m;i++){
if(tot[i]){
cnt++;
if(tot[i]==1) beg=i;
}
}
if(cnt>2)
printf("NO\n"),exit(0);
DFS(beg,0);
}
if(ans[0]!=n)
printf("NO\n"),exit(0);
printf("YES\n");
for(int i=ans[0];i>=1;i--)
if(i==1) printf("%d",ans[i]);
else printf("%d ",ans[i]);
printf("\n");
return 0;
}
【第二题(原始数据)-count】
/*Lucky_Glass*/
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&-x)
const int N=2e5;
int n,m;
long long sum;
int tre[N+5],num[N+5],fal[N+5],pre[N+5],beh[N+5];
void Insert(int pos){
while(pos<=n)
tre[pos]++,
pos+=lowbit(pos);
}
int Query(int pos){
int ret=0;
while(pos)
ret+=tre[pos],
pos-=lowbit(pos);
return ret;
}
int main(){
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
pre[i]=i-1;
beh[i]=i+1;
}
for(int i=n;i>=1;i--){
fal[i]=Query(num[i]-1);
sum+=fal[i];
Insert(num[i]);
}
printf("%lld",sum);
for(int i=1;i<=m;i++){
int pos;scanf("%d",&pos);
if(!fal[pos]){
printf(" %lld",sum);
continue;
}
for(int j=pos;j<=n;j=beh[j])
if(num[j]<=num[pos]){
beh[pre[j]]=beh[j];
pre[beh[j]]=pre[j];
sum-=fal[j];
fal[j]=0;
}
printf(" %lld",sum);
}
printf("\n");
return 0;
}
【第二题(额外数据)-count】
/*Lucky_Glass*/
#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
struct TREEARRAY{
#define lowbit(x) (x&-x)
int tre[N+5];
TREEARRAY(){memset(tre,0,sizeof tre);}
void Insert(int pos,int n){
while(pos<=n)
tre[pos]++,
pos+=lowbit(pos);
}
int Query(int pos){
int ret=0;
while(pos)
ret+=tre[pos],
pos-=lowbit(pos);
return ret;
}
}ary;
struct SEGTREE{
struct NODE{
int l,r,num;
}tre[N*5];
void Update(int u){
tre[u].num=min(tre[u<<1].num,tre[u<<1|1].num);
}
void Init(int a[],int l,int r,int u){
tre[u].l=l;tre[u].r=r;
if(l==r){
tre[u].num=a[l];
return;
}
int mid=(l+r)>>1;
Init(a,l,mid,u<<1);Init(a,mid+1,r,u<<1|1);
Update(u);
}
void Query(int u,int l,int val,long long &sum,int f[]){
if(tre[u].r<l || tre[u].num>val) return;
if(tre[u].l==tre[u].r){
sum-=f[tre[u].l],tre[u].num=(1<<29);
return;
}
int mid=(tre[u].l+tre[u].r)>>1;
if(l>=mid+1) Query(u<<1|1,l,val,sum,f);
else{
Query(u<<1,l,val,sum,f);
Query(u<<1|1,l,val,sum,f);
}
Update(u);
}
}seg;
int n,m;
long long sum;
int f[N+5],num[N+5];
int main(){
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
for(int i=n;i>=1;i--){
sum+=(f[i]=ary.Query(num[i]-1));
ary.Insert(num[i],n);
}
seg.Init(num,1,n,1);
printf("%lld",sum);
for(int i=1;i<=m;i++){
int pos;scanf("%d",&pos);
seg.Query(1,pos,num[pos],sum,f);
printf(" %lld",sum);
}
return 0;
}
The End
Thanks for reading!
- Lucky_Glass
【赛时总结】NOIP2018-三校联考1024的更多相关文章
- 三校联考 Day3
三校联考 Day3 大水题 题目描述:给出一个圆及圆上的若干个点,问两个点间的最远距离. solution 按极角排序,按顺序枚举,显然距离最远的点是单调的,线性时间可解出答案. 大包子的束缚 题目描 ...
- HGOI20180823 三校联考
首测:220qwq(算差的好吧) 后来改了一个地方:300qwq(算慢的好吧) std被踩qwq 注意:输入数据第一行忘记输入n,亲脑补 题解: 多项式除法(若最后除出的答案为1那么就是成功),对于f ...
- 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你
[五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...
- [2019多校联考(Round 6 T3)]脱单计划 (费用流)
[2019多校联考(Round 6 T3)]脱单计划 (费用流) 题面 你是一家相亲机构的策划总监,在一次相亲活动中,有 n 个小区的若干男士和 n个小区的若干女士报名了这次活动,你需要将这些参与者两 ...
- [多校联考2019(Round 5 T1)] [ATCoder3912]Xor Tree(状压dp)
[多校联考2019(Round 5)] [ATCoder3912]Xor Tree(状压dp) 题面 给出一棵n个点的树,每条边有边权v,每次操作选中两个点,将这两个点之间的路径上的边权全部异或某个值 ...
- [多校联考2019(Round 5 T2)]蓝精灵的请求(二分图染色+背包)
[多校联考2019(Round 5)]蓝精灵的请求(二分图染色+背包) 题面 在山的那边海的那边住着 n 个蓝精灵,这 n 个蓝精灵之间有 m 对好友关系,现在蓝精灵们想要玩一个团队竞技游戏,需要分为 ...
- [多校联考2019(Round 5 T3)]青青草原的表彰大会(dp+组合数学)
[多校联考2019(Round 5)]青青草原的表彰大会(dp+组合数学) 题面 青青草原上有n 只羊,他们聚集在包包大人的家里,举办一年一度的表彰大会,在这次的表彰大会中,包包大人让羊们按自己的贡献 ...
- ZR10.1青岛集训三地联考
ZR10.1青岛集训三地联考 谢谢dijk和smy A 题目大意: 已知斐波那契数列\(f\) 设 \[ F_i = \sum_{i = 0}^nf_if_{n - i} \] 求 \[ \sum_{ ...
- 【五校联考1day2】JZOJ2020年8月12日提高组T1 对你的爱深不见底
[五校联考1day2]JZOJ2020年8月12日提高组T1 对你的爱深不见底 题目 Description 出乎意料的是,幸运E 的小R 居然赢了那个游戏.现在欣喜万分的小R 想要写一张明信片给小Y ...
随机推荐
- webpack起步
为什么要使用webpack 很牛逼的样子 https://www.webpackjs.com/comparison/ 基本概念 1. 入口(entry) module.exports = { entr ...
- 编写可维护的 Gruntfile.js
load-grunt-tasks 插件 首先介绍下 load-grunt-tasks 这个插件. 我们一般都会把所有用到的插件以及插件的配置写到 Gruntfile.js 里面,对于小项目来说这个文件 ...
- 菜鸟学习Spring——SpringMVC注解版前台向后台传值的两种方式
一.概述. 在很多企业的开法中常常用到SpringMVC+Spring+Hibernate(mybatis)这样的架构,SpringMVC相当于Struts是页面到Contorller直接的交互的框架 ...
- 《ArcGIS Runtime SDK for Android开发笔记》
开发笔记之基础教程 ArcGIS Runtime SDK for Android 各版本下载地址 <ArcGIS Runtime SDK for Android开发笔记>——(1).And ...
- Flask入门数据库框架flask-SQLAlchemy(十)
Web程序开发中最重要的莫过于关系型数据库,即SQL 数据库,另外文档数据库(如 mongodb).键值对数据库(如 redis)慢慢变得流行. 原因 : 我们不直接使用这些数据库引擎提供的 Py ...
- The content of element type "bean" must match "(description?,(constructor-arg|property|lookup-method|replaced-method)*)".
开发中,总有一下奇奇怪怪的问题 完整的错误就不贴了,异常提示: hibernate.xml] is invalid; nested exception is org.xml.sax.SAXParseE ...
- February 23 2017 Week 8 Thursday
In order to be irreplaceable, one must always be different. 想要无可取代,必须与众不同. In recent days, a news ab ...
- 初识EMC
EMC,即电磁兼容,是指设备在预期的电磁环境中,能按设计要求正常抵抗电磁干扰的能力.其主要包含3个方面:电磁干扰(EMI),电磁抗扰(EMS)与静电放电抗扰(ESD). 电磁干扰的方式可以大概分为传导 ...
- Fiori Launchpad Tile点击后跳转的调试技巧
在SAP Fiori launchpad 里点击某个tile之后,后台会计算出跳转的目标url返回给前台. 下图中一个个白色的方框就成为tile.每个tile点击之后,会打开一个对应的Fiori应用. ...
- python_列表/元组/元组列表以及如何使用
1.list是处理一组有序项目的数据结构 #定义一个列表 list=[1,2,3] print type(list) print list[0] 输出: <type 'list'> 1 2 ...