Atcoder Beginner Contest 407题解A-E

赛时切了4道,E题赛后20分钟就切出来了

AB

#include<bits/stdc++.h>
using namespace std;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int maxi(int x,int y){
	return x<y ? y : x;
}
int mini(int x,int y){
	return x>y ? y : x;
}
int main(){
	int a,b;
	read(a),read(b);
	double p=a*1.0/b;
	double m=ceil(p),n=floor(p);
	if(m-p>p-n) printf("%.0lf",n);
	else printf("%.0lf",m); 
	return 0;
}

其实直接round(p)就可以了,不过赛时没想到

#include<bits/stdc++.h>
using namespace std;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int maxi(int x,int y){
	return x<y ? y : x;
}
int mini(int x,int y){
	return x>y ? y : x;
}
int x,y;
int main(){
	read(x),read(y);
	int ans=0;
	for(int i=1;i<=6;i++){
		for(int j=1;j<=6;j++){
			if(i+j>=x||abs(i-j)>=y){
				++ans;
			}
		}
	}
	printf("%.18Lf",(long double)ans/36);
	return 0;
}

数据范围太小,没必要使用数学方法,暴力枚举即可

C

可以从后向前想:
因为第n位一定是前一个状态加上一个0后,在整体位移a[n]后得到的
所以就能知道在到达n位之前,n-1应该长什么样

(sum表示第i位到第n位的和,ans表示该位所需要的位移次数)

sum+ans≡a[i](mod 10)

ans≡a[i]-sum(mod 10)

由此可知做出第i位所需要的操作次数为(a[i]+10-sum)%10

#include<bits/stdc++.h>
using namespace std;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int maxi(int x,int y){
	return x<y ? y : x;
}
int mini(int x,int y){
	return x>y ? y : x;
}
string s;
int main(){
	cin>>s;
	long long ans=0;
	int sum=0;
	for(int i=s.size()-1;i>=0;i--){
		int k=s[i]-48;
		ans+=(k+10-sum)%10;
		sum=ans%10;//sum及时取余,否则k+10-sum有可能变为负数
	}
	printf("%lld",ans+s.size());
	return 0;
}

D

算法题思维含量就不大了,看到HW<=20 直接暴力dfs即可。
再应用一下位异或的性质,a^a=0 0^a=a
只要算出异或总和,去掉某个值时再异或它一次就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
void read(long long& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
long long maxi(long long x,long long y){
	return x<y ? y : x;
}
int n,m;
long long ans=0;
long long a[maxn][maxn];
bool vis[maxn][maxn];
int wx[4]={0,0,-1,1},wy[4]={-1,1,0,0};
void dfs(int x,int y,long long sum){
	ans=maxi(ans,sum);
	if(y>m) y=1,++x;
	if(x>n) return;
	if(vis[x][y]){
		dfs(x,y+1,sum);
		return;
	}
	for(int i=0;i<4;i++){
		int xi=x+wx[i],yi=y+wy[i];
		if(xi>=1&&xi<=n&&yi>=1&&yi<=m&&(!vis[xi][yi])){
			vis[xi][yi]=vis[x][y]=1;
			dfs(x,y+1,sum^a[x][y]^a[xi][yi]);
			vis[xi][yi]=vis[x][y]=0;
		}
	}
	dfs(x,y+1,sum); 
	return;
}
int main(){
	read(n),read(m);
	long long sum=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			read(a[i][j]);
			sum^=a[i][j];
		}
	}
	dfs(1,1,sum);
	printf("%lld",ans);
	return 0;
}

E

贪心思想,先全拿最大值。
因为括号匹配要求是从后往前k项中右括号数量一定大于左括号数量。
所以从后往前计算,遇到左括号数量大于右括号数了就从中去掉权值最小的那个。
然后在1到i-1中找到最大的还未添加过的,添加上去即可

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+1;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
void read(long long& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
struct num{
	int id; 
	long long p; 
};
bool cmp(num a,num b){
	return a.p>b.p;
}
bool vis[maxn<<1];
num p[maxn<<1];
long long a[maxn<<1];
int n,t;
int main(){
	read(t);
	while(t--){
		read(n);
		for(int i=1;i<=2*n;i++){
			read(p[i].p);
			a[i]=p[i].p;
			p[i].id=i;
		}
		sort(p+1,p+2*n+1,cmp);
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n;i++) vis[p[i].id]=1;
		int cnt=n+1;//候选最大添加值
		int sum=0;
		long long ans=0;
		priority_queue<int,vector<int>,greater<int> > k; //保存当前所有权值中最小的
		for(int i=2*n;i>=1;i--){
			sum+=vis[i];
			ans+=vis[i]*a[i];
			if(vis[i]) k.push(a[i]);
			if((2*n-i+1)-sum<sum&&i>1){//判断左括号数量大于右括号数
				ans-=k.top();
				k.pop();
				--sum;
				while(p[cnt].id>=i){
					++cnt;
				}
				vis[p[cnt].id]=1;
                //这里不需要再添加了,vis设为true后会在后续的遍历中添加上去的
				++cnt;
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

FG

待补

posted @ 2025-05-24 22:40  huangems  阅读(70)  评论(0)    收藏  举报