[题解]ABC347 C~E
Portal:https://atcoder.jp/contests/abc347/tasks
ABC347只过了\(A,B\),再创新低,。。。遂来补题
C - Ideal Holidays
题意简述
输入\(n,a,b,d_1,d_2,…,d_n\),表示在Atcoder国每周分为\(a\)天休息日和\(b\)天工作日,现在有\(n\)个事件,第\(i\)个事件落在第\(d_i\)日。我忘了今天是这一周的第几天,需要你输出这\(n\)个事件是否有可能全部落在休息日。
分析
一开始是对\(n\)个日期取模\(a+b\)然后再求极差\(k\),如果\(k<a\)就Yes
,否则No
……
然后就\(WA\)了一个点。见下:
2 5 1 5 6
\(2\)个事件:\(\{5,6\}\),\(5\)天休息日,\(1\)天工作日。本应输出Yes
,但是输出了No
。这是因为对\(5\)和\(6\)取模\(6\)分别得\(5\)和\(0\),所以只判断极差是不行的。应该把所有\(d[i]\)取模后的结果存在\(d\)中,从小到大排序,然后把两个日期之间的天数(包括\(d[1]+a+b-d[n]\))求最大值。因为\(d[i]\)取值范围是\([0,a+b)\),所以如果两个天数之间差距\(\geq b\)(工作日的天数),就说明这些日期都能安排在休息日。
Code
点击查看代码
#include<bits/stdc++.h> using namespace std; int n,a,b,d[200010]; int main(){ cin>>n>>a>>b; for(int i=1;i<=n;i++){ cin>>d[i]; d[i]%=(a+b); } sort(d+1,d+1+n); int maxx=INT_MIN; for(int i=2;i<=n;i++){ maxx=max(maxx,d[i]-d[i-1]-1); } maxx=max(maxx,d[1]+a+b-d[n]-1); if(maxx>=b) cout<<"Yes\n"; else cout<<"No\n"; }
D - Popcount and XOR
题意简述
给你非负整数\(a,b,C\),构造出非负整数\(X,Y\)满足下列条件:
- \(0 \leq X < 2^{60}\)
- \(0 \leq Y < 2^{60}\)
- \(\operatorname{popcount}(X) = a\)
- \(\operatorname{popcount}(Y) = b\)
- \(X \oplus Y = C\)
\(popcount(X)\)表示\(X\)二进制表示中\(1\)的个数。
\(\oplus\)表示按位异或。
分析
这个题难度其实并不高,但因为赛时跟C鏖战太久并且吃了\(4\)次罚时还没\(A\),所以思路乱了。第二天一想就出来了。
设\(k\)为\(C\)中\(1\)的个数,\(x,y\)分别为\(X,Y\)中,放在\(C\)值为\(1\)的位置上的\(1\)的个数。则有下列关于\(x,y\)的方程组:
\(\begin{cases} a-x=b-y\\ x+y=k \end{cases}\)
则有\(\begin{cases} x=\frac{a-b+k}{2}\\ y=k-x \end{cases}\)
那么我们总结了部分输出No
的情况:
- \((a-b+k)\ mod\ 2\neq 0\)(注意负数\(mod\ 2\)可能等于\(-1\));
- \(x<0,y<0,x\geq a或y\geq b\)。
根据目前的结果,我们可以进行构造了,\(0\leq i<60\),\(cnt0\)和\(cnt1\)分别表示到目前\(s[i]=0和1\)的个数。详见代码。
需要注意的是还有一种输出No
的情况,也就是构造完,\(a\)个\(1\)或者\(b\)个\(1\)没有用完。比如\(a=60,b=60,c=2^{60}-1\),不会被前面的步骤筛查出来,但是发现\(X\)和\(Y\)中一共只能用\(60\)个\(1\),\(a\)和\(b\)没有用完。所以需要定义\(cnt\)来记录填了多少\(1\),每构造完一个就判断如果\(cnt<a\)(如果构造的是\(Y\)就判断\(cnt<b\))就输出No
。
Code
点击查看代码
#include<bits/stdc++.h> #define int long long using namespace std; int a,b,c; signed main(){ cin>>a>>b>>c; bitset<70> s(c),A,B; int k=s.count(); int dx=a-b+k; if(dx%2!=0){ cout<<"-1\n"; return 0; } int x=dx/2,y=k-x; if(x<0||y<0||x>a||y>b){ cout<<"-1\n"; return 0; } int cnt=0; for(int i=0,cnt0=0,cnt1=0;i<60;i++){ if(s[i]==0){ if(cnt0<a-x) A[i]=1,cnt++; cnt0++; }else{ if(cnt1<x) A[i]=1,cnt++; cnt1++; } } if(cnt<a){ cout<<"-1\n"; return 0; } cnt=0; for(int i=0,cnt0=0,cnt1=0;i<60;i++){ if(s[i]==0){ if(cnt0<b-y) B[i]=1,cnt++; cnt0++; }else{ if(cnt1>=x) B[i]=1,cnt++; cnt1++; } } if(cnt<b){ cout<<"-1\n"; return 0; } cout<<A.to_ullong()<<" "<<B.to_ullong()<<"\n"; return 0; }
E - Set Add Query
题意简述
给定\(n,q\),接下来给出\(q\)个数\(x[1],x[2],…,x[q]\)。
定义\(A\)数组初始全为\(0\),集合\(S\)为空,对于\(i=1,2,…,n\),依次进行下列操作:
- 如果\(x[i]\in S\),则把\(x[i]\)从\(S\)中删除。
- 如果\(x[i]\not\in S\),则把\(x[i]\)加入\(S\)。
- 接下来,对于\(j=1,2,…n\),如果\(j\in S\),则\(A[j]+=|S|\)。
(\(|S|\)表示集合\(S\)的大小)
更详细的解释见原题样例。
分析
赛后看的这道题,感觉比C和D简单。
拿下面的样例举例:
5 7 1 2 3 2 5 4 2
如上图,下面的彩色条表示的是某一个数字在哪些步骤时待在\(S\)里。例如\(1\)全程都在\(S\)中,\(2\)中间断了一下,是因为又出现了一个\(2\),所以\(2\)从\(S\)中被删除了。那么我们可以用\(q\)次循环完成这个过程,把每一个区间用\((l,r)\)的形式存在pair
数组中。具体见代码。
处理pair
数组的同时,我们应该把每次操作后\(S\)的大小存下来。用差分+前缀和即可维护出来,存在\(sum\)数组中。接下来输出\(n\)个值,我们就把\(sum\)中\(i\)对应的区间求和输出即可。但是如果循环求和会超时,所以我们需要再求一次前缀和(总体步骤就是差分+前缀和+前缀和)。
https://atcoder.jp/contests/abc347/submissions/51969480的思路与这个相似,但是代码更精简,思路就是用\(k\)表示从\(1\)到\(i\)的长度之和,也是前缀和的方法,但是先减后增,遇到第奇数个数字\(num\)就减去当前的\(k\),遇到第偶数个\(num\)就加上当前的\(k\)。
Code
点击查看代码
#include<bits/stdc++.h> #define int long long using namespace std; int n,q,x[200010],last[200010],cnt; bitset<200010> vis; pair<int,int> p[200010]; int sum[200010],ans[200010]; signed main(){ cin>>n>>q; for(int i=1;i<=q;i++){ cin>>x[i]; if(vis[x[i]]){ vis[x[i]]=0; p[last[x[i]]].second=i-1; }else{ vis[x[i]]=1; p[++cnt].first=i; last[x[i]]=cnt; } } for(int i=1;i<=cnt;i++){ if(p[i].second==0) p[i].second=q; sum[p[i].first]++; sum[p[i].second+1]--; } for(int i=1;i<=q;i++) sum[i]+=sum[i-1]; for(int i=1;i<=q;i++) sum[i]+=sum[i-1]; for(int i=1;i<=cnt;i++){ ans[x[p[i].first]]+=sum[p[i].second]-sum[p[i].first-1]; } for(int i=1;i<=n;i++){ cout<<ans[i]<<" "; } return 0; }
不行太菜了,必须多练了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效