A.AUS

题意:给定三个字符串 \(S1,S2,S3\) ,问是否有一种字符映射方式 \(f\) 使得 \(f(S1)=f(S2)≠f(S3)\)

限制条件:$1≤|S1|,|S2|,|S3|≤10^3 , $总字符串长度和不超过 \(3×10^4\)。

题解:首先如果 \(|S1|≠|S2|\) ,那么 \(f(S1)\) 肯定不等于 \(f(S2)\) ,肯定无解。否则,如果 $ |S1|≠|S3|$ ,那么 \(f(S1)\) 肯定不等于 \(f(S3)\) ,肯定有解。

除此以外的情况,三个字符串的长度都相等。那么 \(S1\) 和 \(S2\) 的每个同位置字符都映射到同一个字符,\(S1\) 和 \(S3\) 至少有一个字符不是映射到同一个字符上。考虑给26个字符变成26个点,那么题目就等价于给 \(S1\) 和 \(S2\) 的每个同位置字符都连上一条边,然后考虑 \(S1\) 和 \(S3\) 是否至少有一个位置的字符不属于同一个连通块。可以简单地使用并查集,时间复杂度 \(O(|S1|+|S2|+|S3|)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long; int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
string a,b,c;
cin>>a>>b>>c;
if(a.length()!=b.length())
{
cout<<"NO\n";
continue;
}
if(a.length()!=c.length())
{
cout<<"YES\n";
continue;
}
vector<ll>fa(30,0);
function<ll(ll)>find=[&](ll u)
{
if(fa[u]==u)return u;
return fa[u]=find(fa[u]);
};
auto merge=[&](ll x,ll y)
{
ll a=find(x),b=find(y);
if(a!=b)fa[a]=b;
};
for(int i=1;i<=26;i++)
{
fa[i]=i;
}
for(int i=0;i<a.length();i++)
{
merge(a[i]-'a'+1,b[i]-'a'+1);
}
bool yw=0;
for(int i=0;i<a.length();i++)
{
if(find(a[i]-'a'+1)!=find(c[i]-'a'+1))
{
yw=1;
break;
}
}
if(yw)cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}

K.Kind of Bingo

题意:有一个 \(n×m\) 的表格,从上到下从左到右依次填上 \(1\) ~ \(n×m\)。给定一个 \(1\) ~ \(n×m\) 的排列 \(p\) ,按照 \(p\) 元素的顺序给表格中对应数字涂色,最多可以交换 \(k\) 次 \(p\) 中两个元素的位置,问最少要操作几次才能涂满表格中的某一行。

限制条件:\(1≤n×m≤10^5,0≤k≤10^9\)。

题解:涂色的一行的数就是 \(km+1\)~\(km+n\)。那么我们可以先计算每行的这些数分别在操作序列中的位次。然后要最小化答案,对于每行来说,如果要让这一行被涂色满,最优方案就是把最后面的k个数移到前面。因此如果 \(k>m\) 答案就是 \(m\) 。否则就是他们中排名 \(m-k+1\) 的数,这是第一个没被移动的数。但也要考虑答案最小为 \(m\),因为至少也要涂色 \(m\) 次,这两个值取 \(max\) 即可。时间复杂度\(O(nm)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long; int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
ll n,m,k,p;
cin>>n>>m>>k;
vector<ll>num[n+7];
for(int i=1;i<=n*m;i++)
{
cin>>p;
num[(p-1)/m].push_back(i);
}
if(k>=m)
{
cout<<m<<'\n';
continue;
}
ll ans=n*m;
for(int i=0;i<n;i++)
{
ans=min(max(m,num[i][m-1-k]),ans);
}
cout<<ans<<'\n';
}
return 0;
}

E. Elevator II

题意:有 \(n\) 个人要坐电梯,每个人要从 \(l_i\) 层到 \(r_i\) 层,都是往上走的。电梯每次只能载一个人,电梯往上每走一个层都要消耗一点电量,往下走不消耗电量。电梯初始在 \(f\) 层,求载完所有人的最小消耗电量和对应的载人序列。

限制条件:\(1≤n≤10^5,1≤l_i≤r_i≤10^9,1≤f≤10^9\)。怎么还有1e9层的楼

题解:每个人往上的路程的花费是必须的,因为电梯只能同时载一个人。我们可以控制的部分是什么呢?是我们从现在的位置到要去载的人的位置的花费。显然我们的位置越高花费就越低,特别注意到,如果我们当前的位置已经比所有的人的位置都高了我们接下来就没有这部分花费了。

因此我们前期移动都是要尽可能地往上走,但是我们可以先往下走载人然后把她载到她的目的地,如果她的目的地的位置比我们原来的位置高,我们就相当于没有额外花费地往上走了一段距离。那么我们就可以想到这样的一个方案:每次检查自身位置下方有没有还没载过并且到达位置比现在高的人,如果有的话直接走就行了。因为你走完了以后只有这个人不能再载了,对于其他人是没有影响的。而这个人由于你已经到达了和她终点一样高的高度,所以你也是没有必要再载她的。如果找不到这样的人的话,那么就不得不往上走了,如果往上走的话我们肯定走离自己距离最近的呀!因为如果你想去别的更高的点,如果这个点的高度比离你最近的点的终点高度低,那么我肯定到最近的点的终点然后再往下走,花费比你直接去这个点少。如果更高呢?那我先到最近的点的点的终点可以少花一段的额外花费呀,怎么看都是更优的。我们就按这个策略一直走到最高点,然后按照高度从高到低载人就行了!

做法的话,首先给所有人按照 \(l\) 从小到大排列,然后维护当前位置在所有人 \(l\) 中的指针和当前位置下面的人的 \(r\) 的最大值 \(ma\),每次检查 \(ma\) 是否比当前位置大,如果是就走到 \(ma\) ,把这个妹妹的牌子添加到答案序列里面,然后用 \(l\) 处于原来位置到 $ma 里面的人的 \(r\) 更新最大值,指针也相应往后移。如果不是就走到现在指针下一位的人的 \(r\),和上面一样地更新数据,还要给答案额外加上你往上走到下一位 \(l\) 的距离。最后就是从后往前扫一遍数组,把不在答案序列里面的人加入到答案序列就行了!时间复杂度主要是排序的复杂度,\(O(n\log n)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct node
{
ll l,r,id;
friend bool operator < (node a,node b)
{
return a.l<b.l;
}
};
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
ll n,f,ans=0;
cin>>n>>f;
vector<node>a(n+7);
vector<ll>id;
vector<bool>yw(n+7,0);
for(int i=1;i<=n;i++)
{
cin>>a[i].l>>a[i].r;
a[i].id=i;
ans+=a[i].r-a[i].l;
}
sort(a.begin()+1,a.begin()+n+1);
ll now=1,ma=-1,wei=-1;
while(now<=n&&a[now].l<=f)
{
if(a[now].r>ma)
{
wei=now;
ma=a[now].r;
}
now++;
}
now--;
while(now<n)
{
if(ma>f)
{
id.push_back(a[wei].id);
yw[wei]=1;
f=ma;
now++;
while(now<=n&&a[now].l<=f)
{
if(a[now].r>ma)
{
wei=now;
ma=a[now].r;
}
now++;
}
now--;
}
else
{
now++;
id.push_back(a[now].id);
yw[now]=1;
ans+=a[now].l-f;
f=a[now].r;
now++;
while(now<=n&&a[now].l<=f)
{
if(a[now].r>ma)
{
wei=now;
ma=a[now].r;
}
now++;
}
now--;
}
}
for(int i=n;i>=1;i--)
{
if(!yw[i])
{
id.push_back(a[i].id);
}
}
cout<<ans<<'\n';
for(int i=0;i<n;i++)
{
cout<<id[i]<<" \n"[i==n-1];
}
}
return 0;
}

H.Heavy-light Decomposition

题意:给定 \(k\) 条链,构造一棵 \(n\) 个点的有根树,使得这个树可以按照轻重链剖分的方式变成这些链,或者报告不可能。

限制条件: \(1≤k≤n≤10^5\)

题解:猜猜题,搓几个样例可以发现,首先固定一条最长的链,设其长度为 \(m\),然后如果其他链长度都小于 \(m\) ,那直接把它连到最长链的链头就行了。那如果有多条等长的最长链呢?那我们还是先固定一条最长链,剩下的链肯定是连到链头最好,因为这样链头下面还有 \(m-1\)个点,就比连上去的 \(m\) 个点少一个,我们只需要找到一条可以连到原来的最长链上面第二个点并且还符合题意的就行了。那么我们偷偷观察一下就可以发现,肯定是选长度最短的链最有可能实现,并且最短链长度是必须小于 \(m-1\) 的,如果最短链长度大于等于 \(m-1\) ,那我们又需要给原来链上面第三个点加配重,但是最短长度已经是 \(m-1\) 了,所以这是不可能的!这样就做完了,我们已经找到了所有的情况。对所有链求最大长度和最小长度的部分,可以用排序也可以直接记录下来,时间复杂度是 \(O(n+k\log k)\) 或者 \(O(n+k)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct node
{
ll l,r;
friend bool operator < (node a,node b)
{
return a.r-a.l<b.r-b.l;
}
};
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
ll n,k;
cin>>n>>k;
vector<node>a(k+7);
for(int i=1;i<=k;i++)
{
cin>>a[i].l>>a[i].r;
}
sort(a.begin()+1,a.begin()+k+1);
vector<ll>fa(n+7,0);
if(k==1)
{
for(int i=1;i<=n;i++)
{
cout<<i-1<<" \n"[i==n];
}
continue;
}
// for(int i=1;i<=k;i++)
// {
// cout<<a[i].l<<' '<<a[i].r<<'\n';
// }
if(a[k].r-a[k].l==a[k-1].r-a[k-1].l&&a[1].r-a[1].l+1>=a[k].r-a[k].l)
{
cout<<"IMPOSSIBLE\n";
continue;
}
if(a[k].r-a[k].l!=a[k-1].r-a[k-1].l)
{
for(int i=1;i<=k;i++)
{
if(i!=k)fa[a[i].l]=a[k].l;
for(int j=a[i].l+1;j<=a[i].r;j++)
{
fa[j]=j-1;
}
}
}
else
{
for(int i=1;i<=k;i++)
{
if(i==1)fa[a[i].l]=a[k].l+1;
else if(i!=k)fa[a[i].l]=a[k].l;
for(int j=a[i].l+1;j<=a[i].r;j++)
{
fa[j]=j-1;
}
}
}
for(int i=1;i<=n;i++)
{
cout<<fa[i]<<" \n"[i==n];
}
}
return 0;
}

M.Make It Divisible

题意:给定一个长度为 \(n\) 的正整数数组 \(a\),你可以给整个数组的每个数都加上一个整数 \(x\) ,要求满足 \(1≤x≤k , k\) 给定。你加完数以后要求满足对于新数组的任意子数组都满足存在一个子数组内的数使得它能够整除子数组内所有数。求出满足题意的 \(x\) 的个数和它们的和。

限制条件:\(1≤n≤5×10^4,1≤a_i,k≤10^9\)。

题解:题目要求的子数组可以等价于子数组的 \(gcd\) 等于它的 \(min\)。注意到我们每次给所有数都加上一个相同的数,它们之间的差是不变的,我们可以从差来考虑。设 \((a_{i+1}+x)-(a_i+x)=c\),不妨设 \(c>0\),如果小于0反过来考虑就行。那么此时 \(a_{i+1}+x\) 是 \(a_i+x\) 的倍数,所以 \(c\) 也是 \(a_i+x\) 的倍数,反过来说,\(a_i+x\) 是 \(c\) 的因数。同时,所有的 \(a_i+x\) 都会是 \(a_{min}+x\) 的倍数(从取整个区间来考虑),也就是任意两个相邻数的差都是 \(a_{min}+x\) 的倍数,所以我们只需要从所有数的 \(gcd\) 的因子里面找答案就行了!考虑枚举 \(gcd\) 的介于 \(a_{min}+1\) 到 \(a_{min}+k\) 之间的因子,这部分是 \(O(\sqrt{a_i} )\)的,那么我们就需要一种 \(O(n)\) 的check方法,想一下怎么check呢?加入一个数要判断是否合法,也就是它左边比它小的数要是它的因子,比它大的数要是它的倍数,并且好像往后就不用再检查比它大的数了,因为区间最小值已经变了!所以我们可以维护一个单调栈,维护到当前位置为止往左的各个区间的最小值,如果 \(a_i+x\) 大于栈顶就检查它是不是栈顶的倍数,然后加入栈;如果小于栈顶就检查栈顶是不是它的倍数,然后栈顶就没用了!继续往后检查,全部检查完就是合法的答案!总时间复杂度 \(O(n\sqrt{a_{i}})\)。好像没到1e5的意思就是并非nlogn的做法,似乎也是个规律?

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long; int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
ll n,k;
cin>>n>>k;
vector<ll>a(n+7);
ll g=0,mi=4e18;
for(int i=1;i<=n;i++)
{
cin>>a[i];
mi=min(mi,a[i]);
if(i>1)g=gcd(g,a[i]-a[i-1]);
}
if(!g)
{
cout<<k<<' '<<(k+1)*k/2<<'\n';
continue;
}
auto check=[&](ll x)
{
vector<ll>st(n+7);
ll top=0;
for(int i=1;i<=n;i++)
{
while(top!=0&&st[top]>(a[i]+x)!=0)
{
if(st[top]%(a[i]+x)!=0)return false;
top--;
}
if(top!=0&&(a[i]+x)%st[top]!=0)
return false;
st[++top]=a[i]+x;
}
return true;
};
ll cnt=0,ans=0;
for(int i=1;i*i<=g;i++)
{
if(g%i==0)
{
if(i-mi<=k&&i-mi>=1&&check(i-mi))
{
cnt++;
ans+=i-mi;
}
//cout<<i<<'\n';
if(i*i!=g&&g/i-mi<=k&&g/i-mi>=1&&check(g/i-mi))
{
cnt++;
ans+=g/i-mi;
//cout<<g/i<<'\n';
}
} }
cout<<cnt<<' '<<ans<<'\n';
}
return 0;
}

点个赞吧QAQ

ICPC2024杭州个人题解的更多相关文章

  1. 【HDU 5934】Bomb(强连通缩点)

    Problem Description There are N bombs needing exploding. Each bomb has three attributes: exploding r ...

  2. 2017 CCPC杭州 题解

    2017CCPC杭州题目PDF Problem A. Super-palindrome 题解: 给你一个字符串,每一步可以将一个字符替换为另一个字符,问你最少多少步可以使得,该字符串任意奇数子串为回文 ...

  3. 【2013杭州区域赛】部分题解 hdu4770—4780

    1008: 题意: 有20W个数,每个数都在20W以内,现在有20W个询问,每次询问L,R区间内不会打架的数有多少个 定义两个数不互质 就会打架 解法: 脑洞很大的一道题,先要进行预处理,对每一个数预 ...

  4. noip2000提高组题解

    事实再次向我证明了RP的重要性... 第一题:进制转换 是我最没有把握AC的一道题目却是我唯一一道AC的题目,真是讽刺.看完题目几乎完全没有往正常的解法(取余倒序)去想,直接写了搜索,因为数据范围在2 ...

  5. 致初学者(一): HDU 2000~ 2013题解

    对于开始学习C语言程序设计或C++程序设计面向过程部分的同学来说,利用在线OJ网站进行实践训练,对提高自己的编程能力很有好处.国内外OJ网站很多,每个都去看看,去刷个题,是不现实的,也没必要.即使一个 ...

  6. HDU100题简要题解(2050~2059)

    HDU2050 折线分割平面 题目链接 Problem Description 我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目.比如,一条折线可以 ...

  7. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  8. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  9. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  10. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

随机推荐

  1. TensorFlow2学习(二):Keras 快速入门

    文章目录1.导入tf.keras2.构建简单模型2.1模型堆叠2.1.1dense :全连接层2.2网络配置3.训练和评估3.1设置训练流程3.2输入Numpy数据3.2.1fit参数详解3.3tf. ...

  2. H265摄像头如何实现网页直播

    介绍 目前安防监控行业,基本所有的摄像头都支持H264编码,但是已经有部分摄像头开始支持H265,并且支持H265的摄像机已经越来越多.H265相比H264有着很多优势,是压缩更高,网络传输消耗的带宽 ...

  3. 2. ur3+robotiq ft sensor+robotiq 2f 140配置gazebo仿真环境

    原文地址: ur3+robotiq ft sensor+robotiq 2f 140配置gazebo仿真环境 ur3+robotiq ft sensor+robotiq 2f 140配置gazebo仿 ...

  4. marktext

    markdown的工具推荐 ps: Typora的替换品,这个工具挺好用的,而且也挺好看. 参考资料: https://www.cnblogs.com/Can-daydayup/p/18105135 ...

  5. excel 批量合并小技巧

    一.批量分割同一个单元格内的内容 1.复制单元格内规则内容2.粘贴到右侧目标单元格3.单击目标单元列4.ctrl+e该方法对不规则长度内容有断字BUG,需要仔细核对二.批量增序之隔行增序1.点击开始单 ...

  6. USB3.0降速/不稳定,或由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备(代码 19)

    在设备管理器的usb设备的属性中,显示提示"由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备".注册表坏了.经过查询,解决方法如下: 方法:打开注册 ...

  7. P3195 [HNOI2008] 玩具装箱 (斜率优化)

    题目描述 一道不限段数的分段问题,要求给出 \(n\) 个元素,求出分任意组所产生的最小代价. 思路 我们可以分为两步来求解这个问题,暴力转移与优化. The First Step 暴力转移 考虑暴力 ...

  8. 我做了个 AI 文档阅读神器,免费开源!

    大家好,我是程序员鱼皮.开学季到了,想必很多朋友要开始收集和阅读论文,像我自己学习新技术知识也会去阅读文档,我深知阅读文档的痛苦.明明每个词拆开都知道什么意思,连一起就看不懂. 为了帮助大家免受文档的 ...

  9. OSI模型-一图胜千言

  10. Java 日志管理的黄金组合: SLF4J+Logback

    slf4j 的前世今生 Log4J.Log4J2和LogBack的历史故事 使用过Log4J和LogBack的同学肯定能发现,这两个框架的设计理念极为相似,使用方法也如出一辙.其实这个两个框架的作者都 ...