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 ...
随机推荐
- [Azure DevOps] 如何使用任务组
1. 使用 PowerShell 脚本 在上一篇文章中我们学会了怎么使用扩展在编译前实时更改版本号.有些情况下我们希望不适用扩展,例如喜欢发明轮子,或者根本没有安装扩展的权限.这时候我们可以自己写 P ...
- Linux命令大全之关机重启命令
1.shutdown [选项] 时间 -r(reboot)重启 -h(halt)关闭 -c(cancel)取消 注:shutdown -h 时间 &(加个&符号再按回车不影响其它操 ...
- DOS命令行(9)——wmic-系统管理命令行工具
wmic 介绍与语法 WMI(Windows Management Instrumentation,Windows 管理规范)是一项核心的 Windows 管理技术:用户可以使用 WMI 管理本地和远 ...
- 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- nohup启动 jar 不输出日志
简单暴力:nohup java -jar xxx.jar >/dev/null 2>&1 &
- 登录华科校园网,我用Socket
登录华科校园网,我用Socket 导语: 找一个华科学生问一问,学校的网络怎么样?得到的大多数是负面回答.其实不论是从覆盖区域.网络稳定性.还是速度来说,华科做的都还是可以的(24:00断网除外).可 ...
- POJ 1873 The Fortified Forest 凸包 二进制枚举
n最大15,二进制枚举不会超时.枚举不被砍掉的树,然后求凸包 #include<stdio.h> #include<math.h> #include<algorithm& ...
- Jenkins 凭证 Devops 的粘合剂
大家好,我是小猿来也,一个热衷于搞 Devops 自动化的 Java 程序猿. 万事具备,只欠东风.当我决定大搞特搞 Devops 的时候,Jenkins 凭证却傻傻分不清. 玩 Devops 的小伙 ...
- Hystrix 使用说明
1.什么情况下会触发 fallback 方法 名字 描述 触发fallback EMIT 值传递 NO SUCCESS 执行完成,没有错误 NO FAILURE 执行抛出异常 YES TIMEOUT ...
- ExtJs4学习(八)数据代理Proxy
ExtJs数据代理我们介绍常用的四种,但会着重介绍ajax代理,因为日常开发中,这个最为常用 Ext.data.proxy.Ajax AjaxProxy(Ajax数据代理类)是你的应用程序中使用最广泛 ...