Codeforces Round #829-1754A+B与1753A+B+C 题解
1754A - Technical Support
题意
给定一个只包含大写字母 Q 和 A 的字符串,如果字符串里的每一个 Q 都能与在其之后的 A 一一对应地匹配,则输出字符串 Yes,否则输出字符串 No。注意,可以有 A 没有被匹配,但每个 Q 必须成功地匹配。
题解
倒着扫一遍,看某一个 Q 后面的 A 的数量是否大于 Q 的数量即可,有一个不满足就说明不可以,全部满足就可以
Code
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n;
char a[N];
inline void Main()
{
cin>>n;
cin>>(a+1);
int cnt=0;
for(int i=n;i;--i)
{
if(a[i]=='A')++cnt;
else
{
if(cnt>0)--cnt;
else return puts("No"),void(0);
}
}
puts("Yes");
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)Main();
return 0;
}
1754B - Kevin and Permutation
题意
给定 1 到 n 的序列,你需要构造一种排列这 n 个数的方式使得任意两个相邻的数的差的绝对值的最小值最大,形式化地说,你需要最大化 minn−1i=1|ai−ai+1|,请给出任意一种构造方式
题解
打个表不难发现 minn−1i=1|ai−ai+1| 的最大值就是 ⌊n2⌋
证明也不难,假设最大值是 ⌊n2⌋+1,首先序列中一定会出现这个元素,那这个元素和它相邻的元素的差的绝对值一定至少有一个小于等于 ⌊n2⌋
若 n 是偶数,直接 n2,n,n2−1,n−1,…,n2+1,1 这样排列就可以了
若 n 是奇数,把 n 放在最开始,后面的和偶数一样排列就行,像这样:n,n−12,n−1,n−12−1,n−2,…,1,n−12+1
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1006;
int n,dis;
inline void Main()
{
cin>>n;
if(n&1)cout<<n<<' ';
dis=n>>1;
for(int i=dis;i;--i) cout<<i<<' '<<i+dis<<' ';
cout<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)Main();
return 0;
}
1753A - Make Nonzero Sum
题意
给定一个长度为 n 的序列,仅由 0,1,−1 组成(简单版题目仅由 1,−1 组成),你需要将这个序列分割为若干段
对于一段 [li,ri] 来说,si 表示这一段中的元素交替加减(第一个元素为加)得到的答案,例如 0,1,−1 这一段的 si=+0−(1)+(−1)=−2
假设一共有 k 段,你需要保证 ∑ki=1si=0
请给出任意一种划分方法,若不存在这样的划分方法,输出 -1
题解
考虑对于某一个元素,不同的划分方法只会改变它对于最终答案的贡献的正负,并不会改变贡献的奇偶性,所以说若所有元素的和为奇数,那么就一定无解
再看序列中的元素仅有 1,−1
由我们上面得到的结论,可以发现在这种情况下一定一共有偶数个元素,考虑对于相邻的两个元素若为 1,1 或 −1,−1,这两个分为一组即可,若为 1,−1 或 −1,1 就分开,单个元素作为一组,这两个区间的贡献加起来也为 0,这样最后的序列一定满足题意
再看困难版本,也就是序列中的元素有 0,1,−1
其实与简单版差别并不大,我们还是把相邻的两个不为 0 的数先分为一组(一定一共有偶数个非零的数字),固定左边界,右边界不断往右扩展,直到找到第二个不为 0 的数字,现在我们只需要想办法让这个区间的贡献为 0 即可
先计算这个区间的贡献,若贡献已经为 0 那就直接使用这个区间,下面考虑贡献不为 0 时
这个区间最右边的元素一定非 0,若这个区间长度为偶数,那最后一个元素计算贡献的时候就会取反,把最后一个元素单独拿出来作为一段,这样就一定能和前面的区间的答案抵消,整个区间的贡献就是 0 了
若区间长度为奇数,我们再分类一下,若区间的第一个元素非 0,就直接把它单独作为一段,后面部分的贡献就会取反,这样就一定能和前面的区间的答案抵消,整个区间的贡献也是 0
若区间长度为奇数,同时区间的第一个元素为 0,就把这个 0 单独作为一段,后面的按照区间长度为偶数的方法处理即可
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,sum,lst1,a[N];
vector<pair<int,int>>ans;
void Main()
{
cin>>n;
lst1=sum=0;
for(int i=1;i<=n;++i)cin>>a[i],sum+=a[i];
if(sum&1)return cout<<"-1\n",void(0);
ans.clear();
for(int i=1,lst=1,f1=-1;i<=n;++i)
{
if(a[i]==0)continue;
lst1=i;
if(f1==-1){f1=i;continue;}
if((((f1-lst+1)&1)?a[f1]:-a[f1])+(((i-lst+1)&1)?a[i]:-a[i])==0)
{
ans.emplace_back(make_pair(lst,i));
lst=i+1;
f1=-1;
continue;
}
if((~(i-lst+1))&1)
{
ans.emplace_back(make_pair(lst,i-1));
ans.emplace_back(make_pair(i,i));
lst=i+1;
f1=-1;
continue;
}
if((i-lst+1)&1)
{
if(a[lst])
{
ans.emplace_back(make_pair(lst,lst));
ans.emplace_back(make_pair(lst+1,i));
lst=i+1;
f1=-1;
continue;
}
else
{
ans.emplace_back(make_pair(lst,lst));
++lst;
--i;
continue;
}
}
}
if(lst1!=n)ans.emplace_back(lst1+1,n);
cout<<ans.size()<<'\n';
for(auto x:ans)cout<<x.first<<' '<<x.second<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)Main();
return 0;
}
1753B - Factorial Divisibility
题意
给定两个正整数 n 和 x 和一个正整数序列 a1,a2,…,an,询问 ∑ni=1ai! 是否能被 x! 整除
题解
显然 k!×(k+1)=(k+1)!,于是乎我们把 ai 装进桶里,从小到大枚举,只要能进位就进位,让 k+1 的阶乘数量加上就好
假设这样进位完毕之后最小的阶乘为 k!,只要 k≥x 就说明可以整除,否则不行
Code
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+1;
int n,x,mn;
int a[N];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>x;
for(int i=1,tmp;i<=n;++i)cin>>tmp,++a[tmp];
for(int i=1;i<=N;++i)
{
a[i+1]+=a[i]/(i+1);
a[i]%=(i+1);
if(a[i])
{
mn=i;
break;
}
}
puts(mn<x?"No":"Yes");
return 0;
}
1753C - Wish I Knew How to Sort
题意
给出一个 01 序列,每次操作会随机选择两个数交换,求期望要多少次操作才能使整个序列单调不降(答案对于 998244353 取模)
题解
假设一共有 c 个 1,显然最终的序列最后 c 个都是 1,假设现在最后 c 个数中有 k 个 1 和 c−k 个 0,那么前面的 n−c 个数中就一定有 c−k 个 1
要希望整个序列单调不降,那就是要把前 n−c 个数中的 1 和后 c 个数中的 0 交换,这样的交换一共有 (c−k)2 种换法,总共的换法为 n(n−1)2,所以成功让后 c 个数中多出一个 1 的概率就是 (c−k)2n(n−1)2=2(c−k)2n(n−1)
期望操作次数就是 n(n−1)2(c−k)2,然后 k 就会增加 1,直到 k 增加到 c 就满足条件了
假设最后 c 个数中一开始有 cnt1 个 1 最终的答案就是
Code
// LUOGU_RID: 91311868
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,mod=998244353;
int n,cnt,k,all,ans;
int a[N];
inline void Mul(int &x,int y){ll z=1ll*x*y;if(z>=mod)z%=mod;x=z;}
inline int mul(int x,int y){ll z=1ll*x*y;if(z>=mod)z%=mod;return z;}
inline void Add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
inline int add(int x,int y){x+=y;if(x>=mod)x-=mod;return x;}
inline int fp(int x,int p)
{
int ans=1;
for(;p;p>>=1,Mul(x,x))if(p&1)Mul(ans,x);
return ans;
}
inline int inv(int x){return fp(x,mod-2);}
void Main()
{
cin>>n;
all=mul(mul(n,n-1),inv(2));
k=ans=cnt=0;
for(int i=1;i<=n;++i)cin>>a[i],cnt+=a[i];
for(int i=n-cnt+1;i<=n;++i)k+=a[i];
for(;k<=cnt;++k)Add(ans,mul(all,inv(mul(cnt-k,cnt-k))));
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)Main();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
2021-10-25 [CSP-S 2021] 廊桥分配 题解