NOI Online 提高组 题解
来补坑了……
个人认为三道题难度差不多……
还有要说一嘴,为啥我在其他网站代码都好好的,复制到 cnblogs 上 Tab 就成 8 空格了?不过也懒得改了。
T1 序列
首先,遇到这种加一减一还带附加条件的基本都是图论题,所以我们用图论的思维去想这道题。将每个 \(a_i\) 看成一个点,并把每个点赋一个新的权值 \(b_i-a_i\),这样最终就是问是否可以把每个点权变为 \(0\)。
先考虑操作二,对每个操作二的点连无向边建图,同一连通块的点可以互相在总和不变的情况下改变为任意值(因为操作二一个加 \(1\) 一个减 \(1\) 是具有传递性的),于是我们可以把连通块用并查集缩点,当成一个权值不变的点看待。
再考虑操作一,在之前缩点的图上对每个操作一连无向边,建好的图必是二分图或非二分图的情况之一。对于二分图,我们可以在左部点与右部点总和之差不变的前提下修改点权,那要保证答案为YES则必然要两边相等;对于非二分图,我们仍从二分图的角度去考虑,相当于左部点或右部点内部出现了连边,那么此时其便无法增加或减少奇数值,只能增减偶数值,进而整幅图的总和都无法增减奇数值。那么要保证答案为YES只能是总和为偶数。
单次复杂度 \(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
int n,m,cnt,a[N],b[N],p[N],q[N],fa[N];
bool vis[N];
ll s[N],c[3];
vector<int> G[N];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
bool dfs(int u,int col)
{
vis[u]=col,c[col]+=s[u];
bool fl=1;
for(int i=0,v;i<G[u].size();++i)
{
if(c[u]==c[v=G[u][i]]) fl=0;
if(!vis[v]&&!dfs(v,3-col)) fl=0;
}
return fl;
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m); cnt=0;
for(int i=1;i<=n;++i) fa[i]=i,G[i].clear(),scanf("%d",a+i);
for(int i=1;i<=n;++i) s[i]=vis[i]=0,scanf("%d",b+i);
for(int i=1,op,x,y;i<=m;++i)
{
scanf("%d%d%d",&op,&x,&y);
if(op==2) fa[find(x)]=find(y);
else p[++cnt]=x,q[cnt]=y;
}
for(int i=1;i<=n;++i) s[find(i)]+=b[i]-a[i];
for(int i=1;i<=cnt;++i)
{
int u=find(p[i]),v=find(q[i]);
G[u].push_back(v);
G[v].push_back(u);
}
bool ok=1;
for(int i=1;i<=n;++i)
if(find(i)==i&&!vis[i])
{
c[1]=c[2]=0;
bool fl=dfs(i,1);
if(fl&&c[1]!=c[2]) {ok=0; break;}
if(!fl&&((c[1]+c[2])&1)) {ok=0; break;}
}
puts(ok?"YES":"NO");
}
return 0;
}
T2 冒泡排序
首先来盘一盘冒泡排序的本质,手玩了几次冒泡排序之后可以很容易发现:一轮冒泡排序就是把每个数的逆序对数减一(如果为零则不用减)。那么我们这道题实际上就是给你一个序列要支持以下操作:单点增减(交换操作实际上只影响了一个点的逆序对个数),全局增减(如果是 \(0\) 则忽略),以及求全局和。忽略 \(0\) 这一个好像不太好搞,但是仍可以用线段树做,比较麻烦,这里不讲。
止步于此,没想出来,遂去无耻地看了题解。其实我们可以用时间为下标维护逆序对个数。具体来说,建立一个树状数组,在 1 号点插入初始序列的逆序对总数,然后再往后的第 \(i+1\) 号点代表了“第 \(i\) 轮冒泡排序后序列的逆序对总数”,这个可以用桶差分 \(O(n\log n)\) 预处理,我们记cnt[i]为“逆序对个数等于 \(i\) 的数的个数”(比较拗口,别咬到舌头了),那么每一轮(假设为第 \(i\) 轮)要减去的逆序对个数就是所有“逆序对个数大于 \(i\) 的数的个数”(还是比较拗口)。对于询问操作,直接求第 \(k\) 轮后的树状数组前缀和即可。
现在来考虑交换操作。分类讨论,假设要交换 \(a_x\) 与 \(a_{x+1}\),如果交换后 \(a_x<a_{x+1}\),那么实际上初始序列的逆序对个数便要减一,那么这个减一的贡献什么时候消失呢?显然是在第 \(b_{x}+2\) 轮(这里b[]是记录每个数逆序对个数的数组,\(b_x\) 是已经交换且减一的值),在这里对应的树状数组上把贡献加回来即可。对于 \(a_x>a_{x+1}\) 可采用同样的逻辑分析,这里不再赘述。
复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
#define lb(x) (x&(-x))
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,a[N],b[N],cnt[N];
ll tot,c[N];
void add(int x,ll k) {for(;x<=n;x+=lb(x)) c[x]+=k;}
ll ask(int x) {ll res=0; for(;x;x-=lb(x)) res+=c[x]; return res;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",a+i);
b[i]=i-1-ask(a[i]);
tot+=b[i],++cnt[b[i]];
add(a[i],1);
}
memset(c,0,sizeof(c));
add(1,tot); tot=0;
for(int i=1;i<=n;++i)
{
tot+=cnt[i-1];
add(i+1,-(n-tot));
}
while(m--)
{
int op,x; scanf("%d%d",&op,&x);
x=min(x,n-1);
if(op==1)
{
swap(a[x],a[x+1]);
swap(b[x],b[x+1]);
if(a[x]<a[x+1])
{
--b[x];
add(1,-1);
add(b[x]+2,1);
}
else
{
++b[x+1];
add(1,1);
add(b[x+1]+1,-1);
}
}
else printf("%lld\n",ask(x+1));
}
return 0;
}
T3 最小环
此题不少人说简单,这只是这道题贪心思路好想却不好证所带来的错觉。(也有可能是我真的菜
首先这道题其实是把一堆数分成若干个环(对于每一个 \(k\),有 \(\gcd(n,k)\) 个环,不知道的话可以做 luogu5887 学习一下)。然后对于每一个环就又回到了 \(k=1\) 的情况。
现在面临两个问题:第一,\(n\) 个数该如何分配到这些环中;第二,每个环中的数该如何排布。
对于问题一,我只知道结论:将 \(n\) 个数排序后,连续的一段分到一个环中(\(a_{1\sim n/\gcd(n,k)}\) 在一个环里,其他以此类推)。现在这个结论我只搜到了 EI 的证明,属实没看懂,太菜了,其他人的题解都省略了(摊手.jpg
对于问题二,继续将在环里的 \(p=n/\gcd(n,k)\) 个数排好序,那么环的排布一定是这样(假设 \(p\) 为奇数,偶数情况类似):
\]
证明:使用归纳法。对于 \(p=1,2,3\) 的情况显然成立,现假设对于 \(p=k\) 的情况成立,考虑 \(p=k+1\) 的情况。
现在 \(k\) 个数已排好,考虑将 \(a_{k+1}\) 插入其中。我们把将 \(a_{k+1}\) 插入 \(a_k,a_{k-1}\) 之间的情况与插入任意两个数 \(a_b,a_c\) 的情况做对比,得到
\]
\]
\]
重新移项得
\]
由排序不等式,证毕。
活整完了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,a[N];
ll f[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",a+i),f[0]+=1LL*a[i]*a[i];
sort(a+1,a+n+1);
while(m--)
{
ll ans=0; int k; scanf("%d",&k);
if(!k) {printf("%lld\n",f[k]); continue;}
int p=n/__gcd(n,k);
if(f[p]) {printf("%lld\n",f[p]); continue;}
for(int i=1;i<=n;i+=p)
{
for(int j=0;j<p-2;++j)
ans+=1LL*a[i+j]*a[i+j+2];
ans+=1LL*a[i]*a[i+1]+1LL*a[i+p-1]*a[i+p-2];
}
printf("%lld\n",f[p]=ans);
}
return 0;
}
NOI Online 提高组 题解的更多相关文章
- noip2010提高组题解
NOIP2010提高组题解 T1:机器翻译 题目大意:顺序输入n个数,有一个队列容量为m,遇到未出现元素入队,求入队次数. AC做法:直接开1000的队列模拟过程. T2:乌龟棋 题目大意:有长度为n ...
- NOIP 2014 提高组 题解
NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...
- NOIP 2001 提高组 题解
NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...
- NOIP 2000 提高组 题解
NOIP2000 提高组 题解 No 1. 进制转换 https://www.rqnoj.cn/problem/295 水题 对于n和基数r, 每次用n mod r, 把余数按照逆序排列 注意 mod ...
- 【NOIP2018】提高组题解
[NOIP2018]提高组题解 其实就是把写过的打个包而已 道路铺设 货币系统 赛道修建 旅行 咕咕咕 咕咕咕
- NOI On Line 提高组题解
(话说其实我想填的是去年CSP的坑...但是貌似有一道题我还不会写咕咕咕... 先写一下这一次的题解吧. T1:序列.题意省略. 两种操作.这种题要先分析部分分 给出了全部都是2操作的子任务. 发现A ...
- noip2009提高组题解
NOIP2009题解 T1:潜伏者 题目大意:给出一段密文和破译后的明文,一个字母对应一个密文字母,要求破译一段密文,如果有矛盾或有未出现密文无法破译输出failed,否则输出明文. 思路:纯模拟题 ...
- noip2008提高组题解
第一题:笨小猴 模拟 第二题:火柴棒等式 搜索 深搜不用说,确定出两个加数然后判断能否拼出等式. 枚举确实不太好搞,因为枚举范围不确定,太大了容易超时,太小了容易漏解.不过这题的数据貌似很温和,我 ...
- noip2007提高组题解
题外话:这一年的noip应该是最受大众关心的,以至于在百度上输入noip第三个关键字就是noip2007.主要是由于这篇文章:http://www.zhihu.com/question/2110727 ...
随机推荐
- jemeter压测, 高级应用: 发1万个请求,每个请求参数都不同, 使用CSV数据文件配置
今天接到一个压测任务, 数据源需要自己从测试环境库中取, 并且使用jemeter 请求, 每个请求参数都不相同 这里使用jemeter的 CSV数据文件来配置: 这样配置好后, 开始发送请求: csv ...
- 10: java数据结构和算法: 构建哈夫曼树, 获取哈夫曼编码, 使用哈夫曼编码原理对文件压缩和解压
最终结果哈夫曼树,如图所示: 直接上代码: public class HuffmanCode { public static void main(String[] args) { //获取哈夫曼树并显 ...
- .Net RabbitMQ实战指南——进阶(二)
持久化 持久化可以提高RabbitMQ的可靠性,防止异常情况下的数据丢失.RabbitMQ的持久化分为三个部分:交换器的持久化.队列的持久化和消息的持久化. 交换器的持久化通过声明队列时将durabl ...
- <题解>幻想乡战略游戏
洛谷题目 看到题面,很容易就想到,这是要你找树上的重心,只不过这个重心是在带边权的树上 所以对于这个我们在树上找这个重心 一开始我想的是,我要更新权值,然后把每个点的答案更新一下 就取最大值,这好像是 ...
- LuatOS | 全新在线模拟器,随时随地发挥创意
LuatOS --运行在嵌入式硬件的实时操作系统,开启全新物联网生态. 聚焦嵌入式应用生态,内置功能可支持绝大多数物联网应用场景.深度整合Lua语言,只需少量内存和Flash空间就能运行.不局限于合宙 ...
- 【NLP学习其二】什么是隐马尔可夫模型HMM?
概念 隐马尔可夫模型描述的是两个时序序列联合分布p(x,y)的概率模型,其中包含了两个序列: x序列外界可见(外界指的是观测者),称为观测序列(obsevation seuence) y序列外界不可见 ...
- 最佳实践丨使用Rancher轻松管理上万资源不是梦!
前 言 Rancher 作为一个开源的企业级 Kubernetes 集群管理平台.你可以导入现有集群,如 ACK.TKE.EKS.GKE,或者使用 RKE.RKE2.K3s 自定义部署集群. 作为业界 ...
- 『无为则无心』Python基础 — 15、Python流程控制语句(for循环语句)
目录 1.for循环语法 2.for循环中的break和continue 3.循环+else结构 (1)while...else (2)while...else退出循环的方式 (3)for...els ...
- CVPR2021 | 开放世界的目标检测
本文将介绍一篇很有意思的论文,该方向比较新,故本文保留了较多论文中的设计思路,背景知识等相关内容. 前言: 人类具有识别环境中未知对象实例的本能.当相应的知识最终可用时,对这些未知实例的内在好奇心 ...
- 07 修改JumpServer网页信息
1.7.修改JumpServer网页信息 注意:在修改相关配置文件之前要先进行备份,防止文件修改错误无法恢复. 1.Luna图标: /opt/luna/static/imgs/logo.png 2.j ...