[题解]AtCoder Beginner Contest 386(ABC386) A~E
A - Full House 2
容易发现,答案为Yes
\(\iff\)输入中恰好出现了\(2\)种不同的数,可以用set
等数据结构来计算不同元素的个数。
点击查看代码
#include<bits/stdc++.h> using namespace std; set<int> se; signed main(){ for(int i=1,a;i<=4;i++){ cin>>a; se.insert(a); } cout<<(se.size()==2?"Yes":"No"); return 0; }
B - Calculator
从头遍历字符串,贪心将现有的00
替换成0
即可。
点击查看代码
#include<bits/stdc++.h> using namespace std; string s; int n,cnt; signed main(){ cin>>s; n=s.size(); s=s+' '; for(int i=0;i<n;i++){ if(s[i]=='0'&&s[i+1]=='0') i++; cnt++; } cout<<cnt<<"\n"; return 0; }
C - Operate 1
设\(|s|=n,|t|=m\),则根据\(n,m\)的大小关系讨论:
-
\(|n-m|>1\):
No
。 -
\(n+1=m\):双指针\(i,j\)分别指向\(s[0],t[0]\)开始匹配:
- 如果\(s[i]\ne t[j]\),则\(j\leftarrow (j+1)\)。
- 如果\(s[i]=t[j]\),则\(i\leftarrow (i+1)\),\(j\leftarrow (j+1)\)。
如果中途失配次数\(\le 1\),则
Yes
,否则No
。 -
\(m+1=n\):交换\(s,t\),然后同\(n+1=m\)的做法。
-
\(n=m\):\(s,t\)不匹配的位置\(\le 1\),则
Yes
,否则No
。
点击查看代码
#include<bits/stdc++.h> using namespace std; int n,m,k; string s,t; bool solve(){ if(abs(n-m)>1) return 0; if(n==m){ int cnt=0; for(int i=0;i<n;i++) cnt+=(s[i]!=t[i]); return cnt<=1; } if(n-1==m) swap(s,t); bool f=0; for(int i=0,j=0;i<n;i++,j++){ if(s[i]!=t[j]){ if(f) return 0; else f=1,i--; } } return 1; } signed main(){ cin>>k>>s>>t; n=s.size(),m=t.size(); cout<<(solve()?"Yes":"No")<<"\n"; return 0; }
题解还提供了一种做法:删掉\(s,t\)相同的前缀和后缀,如果最终\(|s|\le 1\)且\(|t|\le 1\),则为Yes
,否则No
。
D - Diagonal Separation
下文的“块”均指已被着色的方格。
容易发现,答案合法\(\iff\)不存在一个黑色块在一个白色块的右下方。
证明
因为根据题意,每个黑色块上面和左边的所有格子都必须是黑色,每个白色块下面和右边的所有格子都必须是白色。
如果存在一个黑色块在一个白色块的右下方,它们所管辖范围就会产生两个交点,这两个交点无法同时满足黑色与白色,所以不合法;否则显然合法。
根据这个结论,也相当于判断是否每个黑块左上方都没有白块。
所以我们可以按行从小到大为第一关键字,列从小到大为第二关键字。
-
对于当前遍历到的白块\((x,y)\),将\(y\)加入
set
。 -
对于当前遍历到的黑块\((x,y)\),存在
set
中的,有且仅有\(1\sim(x-1)\)行的所有白块,和第\(x\)行第\((1\sim y)\)列的所有白块。显然答案只可能在它们之中。这些白块已经满足了在\((x,y)\)上方,仅需再限制在\((x,y)\)左边即可,即查找
set
中是否存在值\(k\le y\),可以用二分查找实现。
时间复杂度\(O(m\log m)\)。
点击查看代码
#include<bits/stdc++.h> using namespace std; struct Point{int x,y;char c;}; bool cmp(Point a,Point b){return a.x==b.x?(a.y==b.y?a.c=='W':a.y<b.y):a.x<b.x;} vector<Point> a; set<int> se; int n,m; bool solve(){ for(Point i:a){ if(i.c=='W') se.insert(i.y); else if(se.upper_bound(i.y)!=se.begin()) return 0; } return 1; } signed main(){ cin>>n>>m; for(int i=1;i<=m;i++){ int x,y;char c; cin>>x>>y>>c; a.emplace_back((Point){x,y,c}); } sort(a.begin(),a.end(),cmp); cout<<(solve()?"Yes":"No")<<"\n"; return 0; }
虽然题目限制了被着色的方格互不相同,但为了让代码更健壮,我处理了这种情况,对于相同的\((x,y)\),在排序时令白格子在前。
E - Maximize XOR
如果暴搜,时间复杂度将是\(O(C_n^k\times k)\),无法通过……吗?
的确是这样,就算题目限制了\(C_n^k\le 10^6\),在\(k\)较大的情况下仍会严重超时。
但我们知道\(C_n^k=C_n^{n-k}\),所以当\(k>\frac{n}{2}\),让\(k\leftarrow (n-k)\),枚举的就是不选哪些数。时间复杂度变成了\(O(C_n^k\times \min(k,n-k))\)。
这样的时间复杂度是可以通过的,下面是感性理解:
- 经计算,在\(n\ge 23\)时,要想使得\(C_n^k\le 10^6\),就必须使\(k<10\),再往后\(k\)会更小,所以时间复杂度不会超过\(O(10^6\times 10)\)。
- 而在\(n<23\)时,由于\(k\le \frac{n}{2}\),所以时间复杂度也不会超过\(O(10^6\times 11)\)。
点击查看代码
#include<bits/stdc++.h> #define N 200010 #define int long long using namespace std; int n,k,a[N],p[N],tmp,ans; void dfs(int pos,int cnt){ if(pos>k){ int x=tmp; for(int i=1;i<=k;i++) x^=a[p[i]]; ans=max(ans,x); return; } for(int i=cnt;i<=n-k+pos;i++){ p[pos]=i; dfs(pos+1,i+1); } } signed main(){ cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; if(k>n/2){ k=n-k; for(int i=1;i<=n;i++) tmp^=a[i]; } dfs(1,1); cout<<ans<<"\n"; return 0; }
F - Operate K
补题中……
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!