持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情
时隔好久又一次出 E 了qwq!
题目链接
Dashboard - Codeforces Round #829 (Div. 2) - Codeforces
A Technical Support
题目大意
您在一家大公司的技术支持质量控制部门工作。您的工作是确保所有客户问题都已得到解决。
今天,您需要检查客户和技术支持经理之间的聊天记录。根据工作规则,客户的每条消息都回答。然而,有时客户提出问题的速度如此之快,以至于经理对旧问题的一些回答出现在客户提出一些新问题之后。
由于隐私政策,您无法获得消息的全文,只能看到消息的顺序以及每条消息的类型:客户问题或技术支持经理的回复。保证对话以客户的问题开始。
您必须确定,此对话是否符合上述工作规则。
思路
判断每个“Q”后面是否都有对应的“A”,即任意时刻后缀“A"的数量不少于后缀“Q”的数量,倒序遍历字符串统计一下即可。
代码
#include <bits/stdc++.h>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
const int N=500001;
char ch[N];
int n;
int solve()
{
scanf("%d",&n);
cin>>ch+1;
int Q=0,A=0;
for (int i=n;i>=1;--i)
{
if (ch[i]=='Q') Q++;
else A++;
if (A<Q) return 0;
}
return 1;
}
int main()
{
int T=1;
for (scanf("%d",&T);T--;)
if (solve()) yyy;
else nnn;
return 0;
}
B Kevin and Permutation
题目大意
求一个 1 到 的排列,要求相邻两个元素之差的最小值最大。
思路
易知一个 1 到 的排列相邻两个元素之差的最小值最大是 。
一个正确的构造方法是
代码
#include <bits/stdc++.h>
using namespace std;
int n,m,k;
int solve()
{
scanf("%d",&n);
for (int i=1,j=n/2+1;j<=n;++i,++j)
{
printf("%d ",j);
if (i<=n/2) printf("%d ",i);
}
printf("\n");
return 0;
}
int main()
{
int T=1;
for (scanf("%d",&T);T--;) solve();
return 0;
}
C1+C2 Make Nonzero Sum
题目大意
给定长度为 的数组 ,元素的取值仅有可能是 。
将整个数组划分成若干段,第 段 的权值 。
输出任何一种使得所有划分的区间的权值和恰好为 0 的划分方案,无解输出 -1。
思路
没看懂 C1 有什么特殊之处……读了 C1 之后写了一发发现可以把 C2 过掉……
由于不需要最小化划分出的段的数量,一个长度为 3 的段可以分成一个长度为 2 的段和一个长度为 1 的段,一个长度为 4 的段可以分成 2 个长度为 2 的段……不影响最终的权值和。即我们划分出的段的长度最长为 2。
我们先假设把原数组划分成 段,即每一个元素划分一段,我们只需要考虑让哪些段和前一个段合并,形成长度为 2 的段即可。则原问题转化为从 2 到 中选择若干个不相邻的下标让其中的元素乘上 -1,使得数组中所有元素的和为 0。而在我们数组中的元素取值仅有可能是 的情况下:
- 让一个 1 乘 -1,则使得所有元素之和减少 2
- 让一个 -1 乘 -1,则使得所有元素之和增加 2
- 让 0 乘 -1 无任何改变
记原数组中所有元素之和为 ,则:
- 如果 是 0,无需操作
- 如果 是奇数,无解
- 如果 ,我们需要找 个互不相邻的 1,使其乘上 -1
- 如果 ,我们需要找 个互不相邻的 -1,使其乘上 -1
在数组中找 k 个不相邻的 1(或 -1)显然可以贪心求解,取可以取的最靠前的元素即可。由上文,使得一个元素乘上 -1,即使其和前一个元素位于同一个段,按要求输出划分方案。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=500001;
int v[N],a[N],n,m;
int solve()
{
for (int i=0;i<=n;++i) v[i]=0;
scanf("%d",&n);
int sum=0;
for (int i=1;i<=n;++i) scanf("%d",&a[i]),sum+=a[i];
if (sum%2) return printf("-1\n"),0;
int f=0;
m=n;
if (sum>0) f=1;
else f=-1;
for (int i=2;i<=n&∑++i)
{
if (a[i]==f&&v[i-1]!=1)
{
m--;
v[i]=1;
sum-=2*f;
}
}
if (sum!=0) return printf("-1\n"),0;
printf("%d\n",m);
for (int l=1,r=1;r<=n;l=r=r+1)
{
if (v[r+1]) r++;
printf("%d %d\n",l,r);
}
}
int main()
{
int T=1;
for (scanf("%d",&T);T--;) solve();
return 0;
}
D Factorial Divisibility
题目大意
给出 和 ,判断 能否整除 。
思路
,判断所有比 小的阶乘是否能全部凑成 即可。
代码
#include <bits/stdc++.h>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
const int N=500001;
int n,m,k;
int v[N];
int solve()
{
scanf("%d",&n);
scanf("%d",&k);
for (int i=1,x;i<=n;++i)
{
scanf("%d",&x);
v[x]++;
}
for (int i=1;i<k;++i)
{
v[i+1]+=v[i]/(i+1);
v[i]%=(i+1);
if (v[i]!=0) return 0;
}
return 1;
}
int main()
{
if (solve()) yyy;
else nnn;
return 0;
}
E Wish I Knew How to Sort
题目大意
给一个长度为 的 01 数组 。每次操作等概率的选择一对下标 ,如果 就交换它们的值。
求希望执行多少次操作可以使数组不降。
思路
没开 long long 答案错误两发血亏(
统计整个数组中 0 的数量 ,再统计前 个元素中有多少个 1,记作 。容易发现 表示有多少个 0 不在应该在的位置上。
我们定义一次成功的操作需要满足以下条件:
一次成功的操作可以使 减少 1,不满足上述条件的操作则不改变 。
共有 个可能被选择的下标对,其中成功的操作有 个,则一次操作是有效的的概率为 。设 表示从当前状态使 减少 1 的期望操作步数,则:
即执行了 1 次操作后,有 的概率本次操作为有效操作,还需要进行 0 次即可使 减少 1,有 的概率还需要进行 次才能使 减少 1。
解得:
使 变为 0 时,没有 0 不在应该在的位置上,数组单调不降。
对 循环计算求和即可。
代码
#include <bits/stdc++.h>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
const int N=500001;
const LL mod=998244353;
int n,m,k;
int a[N];
LL inv[N];
LL poww(LL a,LL b)
{
LL ans=1;
for (;b;b>>=1,a=a*a%mod)
if (b&1) ans=ans*a%mod;
return ans;
}
int solve()
{
scanf("%d",&n);
int cnt=0,cnt0=0;
for (int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if (a[i]==0) cnt++;
}
for (int i=cnt+1;i<=n;++i)
if (a[i]==0) cnt0++;
LL ans=0;
for (int i=cnt0;i>=1;--i)
{
ans+=(1ll*n*(n-1)/2)%mod*inv[i]%mod;
ans%=mod;
}
printf("%lld\n",ans);
return 1;
}
int main()
{
int T=1;
inv[0]=1;
for (int i=1;i<=200000;++i) inv[i]=poww(1ll*i*i,mod-2);
for (scanf("%d",&T);T--;) solve();
return 0;
}