[题解]AtCoder Beginner Contest 384(ABC384) A~F

A - aaaadaa

按题意模拟即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
char c1,c2;
string s;
signed main(){
	cin>>n>>c1>>c2>>s;
	for(int i:s){
		if(i==c1) cout<<c1;
		else cout<<c2;
	}
	return 0;
}

B - ARC Division

按题意模拟即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,r,d,a;
signed main(){
	cin>>n>>r;
	while(n--){
		cin>>d>>a;
		if(d==1){
			if(r>=1600&&r<=2799) r+=a;
		}else{
			if(r>=1200&&r<=2399) r+=a;
		}
	}
	cout<<r;
	return 0;
}

C - Perfect Standings

枚举得分情况,按分数从大到小为第一关键字,字典序从小到大为第二关键字进行排序,输出即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int a[5],idx;
struct ttt{int num;string s;}ans[514];
signed main(){
	for(int i=0;i<5;i++) cin>>a[i];
	for(int i=1;i<32;i++){
		string s="";
		int sum=0;
		for(int j=0;j<5;j++){
			if((i>>j)&1) s+=('A'+j),sum+=a[j];
		}
		ans[++idx]={sum,s};
	}
	sort(ans+1,ans+1+idx,[](ttt a,ttt b){
		return a.num==b.num?a.s<b.s:a.num>b.num;
	});
	for(int i=1;i<=idx;i++) cout<<ans[i].s<<"\n";
	return 0;
}

D - Repeated Sequence

\(t=\sum_{i=1}^n a[i]\),则满足条件的区间,去除中间完整的周期,剩下的部分就是\(a\)的一个前缀和一个后缀,它们的和最大是\(2\times (s\bmod t)\),所以我们只需要判断是否存在一个前缀和一个后缀的和是\((s\bmod t)\)\((s\bmod t)+t\)即可,可以用map将所有前缀和(包括\(0\))扔进去。

注意特判\(s<t\)时必须仅计算\((s\bmod t)\)的答案。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 200010
using namespace std;
int n,s,a[N],pa[N];
unordered_set<int> se;
signed main(){
	cin>>n>>s;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) pa[i]=pa[i-1]+a[i],se.insert(pa[i]);
	se.insert(0);
	int sum=s%pa[n];
	bool f=0;
	for(int i=1;i<=n;i++){
		int sa=pa[n]-pa[i-1];
		if(se.count(sum-sa)){
			f=1;
			break;
		}
	}
	if(f){
		cout<<"Yes\n";
		return 0;
	}
	if(s>=pa[n]){
		sum+=pa[n];
		for(int i=1;i<=n;i++){
			int sa=pa[n]-pa[i-1];
			if(se.count(sum-sa)){
				f=1;
				break;
			}
		}
		if(f){
			cout<<"Yes\n";
			return 0;
		}
	}
	cout<<"No\n";
	return 0;
}

赛后看了其他题解,其实没必要那么麻烦,将每个后缀丢进set后,依次遍历每个前缀\(a[1\sim i]\),如果\(s\ge a[i]\)且存在一个后缀的值为\((s-a[i])\bmod t\),就是合法的。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 200010
using namespace std;
int n,s,a[N];
unordered_set<int> se;
bool solve(){
	for(int i=0;i<n;i++) se.insert(a[n]-a[i]);
	for(int i=0;i<n;i++){
		if(s<a[i]) return 0;
		if(se.count((s-a[i])%a[n])) return 1;
	}
	return 0;
}
signed main(){
	cin>>n>>s;
	for(int i=1;i<=n;i++) cin>>a[i],a[i]+=a[i-1];
	cout<<(solve()?"Yes\n":"No\n");
	return 0;
}

E - Takahashi is Slime 2

优先队列维护可扩展到的格子的力量值,每次取最小判断能否扩展,如果能扩展就累加答案并更新可扩展到的格子,否则直接输出答案。

时间复杂度\(O(nm\log nm)\)

点击查看代码
#include<bits/stdc++.h>
#define N 510
#define M 510
#define int long long
using namespace std;
int n,m,lim,sx,sy,a[N][M],dx[4]{-1,0,1,0},dy[4]{0,1,0,-1};
bitset<M> vis[N];
struct Status{int v,x,y;};
struct cmp{bool operator()(Status a,Status b){return a.v>b.v;}};
priority_queue<Status,vector<Status>,cmp> q;
signed main(){
	cin>>n>>m>>lim>>sx>>sy;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	vis[sx][sy]=1;
	for(int i=0;i<4;i++){
		int xx=sx+dx[i],yy=sy+dy[i];
		if(xx<1||yy<1||xx>n||yy>m) continue;
		q.push({a[xx][yy],xx,yy});
		vis[xx][yy]=1;
	}
	int V=a[sx][sy];
	while(!q.empty()){
		auto t=q.top();
		q.pop();
		int v=t.v,x=t.x,y=t.y;
		if(v>=(V+lim-1)/lim) break;
		V+=v;
		for(int i=0;i<4;i++){
			int xx=x+dx[i],yy=y+dy[i];
			if(xx<1||yy<1||xx>n||yy>m||vis[xx][yy]) continue;
			q.push({a[xx][yy],xx,yy});
			vis[xx][yy]=1;
		}
	}
	cout<<V;
	return 0;
}

F - Double Sum 2

不难发现,\(f(x)\)表示将\(x\)二进制表示下的后导零去除的结果。

因此,考虑枚举两个数和二进制表示中 末尾\(0\)的数量。

两个数的和的末尾有至少\(k\)\(0\),当且仅当他们的后\(k\)位相加为\(2^k\)。可以开一个桶来统计\(a[i]\)的后\(k\)位的值,对于每个\(k\),可以\(O(n)\)统计出\(f[k]\),即“两个数的和的末尾有至少\(k\)\(0\)”的所有\(a[i]+a[j]\)之和。

\(f\)求差分数组,即可得到\(g[k]\),即“两个数的和的末尾有恰好\(k\)\(0\)”的所有\(a[i]+a[j]\)之和。答案即为\(\sum\limits_{i=0} g[i]\div 2^i\)

时间复杂度\(O(n\log V)\)

点击查看代码
#include<bits/stdc++.h>
#define N 200010
#define int long long
using namespace std;
int inv(int x,int s){return s&(s+1-(x&s));}
int n,a[N],sum[1<<26],cnt[1<<26],f[26],ans;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int k=25;~k;k--){
		int s=(1<<k)-1;
		for(int i=1;i<=n;i++){
			sum[a[i]&s]+=a[i],cnt[a[i]&s]++;
			f[k]+=sum[inv(a[i],s)]+cnt[inv(a[i],s)]*a[i];
		}
		for(int i=1;i<=n;i++) sum[a[i]&s]=cnt[a[i]&s]=0;
		ans+=(f[k]-f[k+1])>>k;
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2024-12-15 22:56  Sinktank  阅读(5)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.