Atcoder Beginner Contest 422 A-F

A

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int a,b;
int main(){
	read(a),read(b);
	++b;
	if(b>8) b=1,++a;
	printf("%d-%d",a,b);
	return 0;
}
//^o^

B

这里指的是上下左右相邻的四个格子,别理解错了

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
void read(char& c){
	do{
		c=getchar();
	}while(c==32||c==10||c==13);
}
char mp[maxn][maxn];
int n,m;
int wx[4]={0,0,-1,1},wy[4]={-1,1,0,0};
int main(){
	read(n),read(m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			read(mp[i][j]);
		}
	}
	bool ans=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(mp[i][j]=='.') continue;
			int cnt=0;
			for(int k=0;k<4;k++){
				int xi=i+wx[k],yi=j+wy[k];
				if(xi>=1&&xi<=n&&yi>=1&&yi<=m){
					cnt+=mp[xi][yi]=='#';
				}
			}
			ans&=(cnt==2||cnt==4);
		}
	}
	if(ans) printf("Yes");
	else printf("No");
	return 0;
}
//^o^

C

耗时 \(1\) 小时,交了 \(6\) 发,没做出来 TT

首先肯定把 \(B\) 都用光,然后考虑 \(A\)\(C\)

其实肯定有公式的,不过也可以无脑三分

代码写的是三分(我把右边界写错赛时没调出来)

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
void read(char& c){
	do{
		c=getchar();
	}while(c==32||c==10||c==13);
}
char mp[maxn][maxn];
int n,m;
int wx[4]={0,0,-1,1},wy[4]={-1,1,0,0};
int main(){
	read(n),read(m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			read(mp[i][j]);
		}
	}
	bool ans=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(mp[i][j]=='.') continue;
			int cnt=0;
			for(int k=0;k<4;k++){
				int xi=i+wx[k],yi=j+wy[k];
				if(xi>=1&&xi<=n&&yi>=1&&yi<=m){
					cnt+=mp[xi][yi]=='#';
				}
			}
			ans&=(cnt==2||cnt==4);
		}
	}
	if(ans) printf("Yes");
	else printf("No");
	return 0;
}
//^o^

\(upd\,\,on\,\,2025.9.9\)

更好的做法,本来是从一位巨佬的交谈中得知的,然后发现和官解是一样的

他说他是凑出来的,这里来证明这种做法

先给公式:

\[ans=Min(Min(a,c),(a+b+c)/3) \]

由于 \(ABC\)\(ACC\)\(AAC\) 都需要至少一个 \(A\)\(C\)

所以 \(Min(a,c)\) 是能组成个数的上限

然后考虑不能达到上限的情况

\(Min(a,c)>(a+b+c)/3\) ,也就是说,此时 \(a,c\) 均大于 \((a+b+c)/3\)

那么只要一定可以组成 \((a+b+c)/3\) 个形如 \(A?C\) 的框架

并将剩下的东西填到中间去,由于保证可以存在 \((a+b+c)/3\) 个三元组,那么填进去的东西也一定是够的

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int t;
int a,b,c;
int main(){
	read(t);
	while(t--){
		read(a),read(b),read(c);
		printf("%lld\n",min((LL)min(a,c),((LL)a+b+c)/3));
	}
	return 0;
}
//^o^

D

看到这个,很容易想到分治

分治的时候尽量把两边弄均匀

只有在奇数的时候,分配时会产生 \(1\) 的差值

发现答案不是 \(0\) 就是 \(1\)

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=2e6+5;
const int max2=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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int n,k;
int ans=0;
int a[maxn];
void solve(int l,int r,int p,int g){
	if(l==r){
		a[l]+=p;
		return;
	}
	int mid=(l+r)>>1;
	ans|=(p&1);
	solve(l,mid,p/2,g+1),solve(mid+1,r,(p+1)/2,g+1);
}
int main(){
	read(n),read(k);
	n=(1<<n);
	int p=k/n;
	k%=n;
	solve(1,n,k,0);
	printf("%d\n",ans);
	for(int i=1;i<=n;i++){
		printf("%d ",p+a[i]);
	}
	return 0;
}
//^o^

E

随机找两个点,这两个点在一条覆盖一半点的直线上的概率约为 \(\frac{1}{4}\)

\(5e5\) 的数据范围,找个 \(1000\) 次绝对够了

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
mt19937 rd(time(NULL));
const int maxn=5e5+5;
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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int n;
int x[maxn],y[maxn];
int main(){
	read(n);
	for(int i=1;i<=n;i++){
		read(x[i]),read(y[i]);
	}
	for(int i=1;i<=1000;i++){
		int a=rd()%n+1,b=rd()%n+1;
		while(a==b) b=rd()%n+1;
		LL p=y[b]-y[a],q=x[a]-x[b];
		LL c=-1ll*p*x[a]-1ll*q*y[a];
		//cout<<a<<' '<<b<<' '<<p<<' '<<q<<' '<<c<<endl;
		int cnt=0;
		for(int j=1;j<=n;j++){
			if(p*x[j]+q*y[j]+c==0){
				//cout<<j<<' ';
				++cnt;
			}
		}
		//cout<<endl;
		if(cnt>=(n+1)/2){
			printf("Yes\n%lld %lld %lld",p,q,c);
			return 0;
		}
	}
	printf("No");
	return 0;
}
//^o^

F

\(upd\,\, on \,\,2025.9.9\)

由于同时和点权和路径长度产生联系,所以是不能用 \(dijkstra\) 解决的

对于一条长为 \(n\) 的路径,我们发现它的点权的权值是这样的

\[n,n-1,n-2,...,3,2,1,0 \]

于是我们可以设计状态 \(dp[i][j]\) 表示点 \(j\) 作为路径长度为 \(i\) 的路径的起点,其从 \(1\) 开始到 \(j\) 所花费的最小油费

即它的点权的权值应该为 \(i\)

状态转移显然:

\[dp[i][j]=min(dp[i][j],dp[i+1][v]+i*w[j]) \]

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=5005,maxm=5005;
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<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int head[maxn],nxt[maxm<<1],e[maxm<<1];
int mp_cnt;
void init_mp(){
	memset(head,-1,sizeof(head));
	mp_cnt=-1;
}
void add_edge(int u,int v){
	e[++mp_cnt]=v;
	nxt[mp_cnt]=head[u];
	head[u]=mp_cnt;
}
struct node{
	int u;
	LL p;
};
int n,m;
int w[maxn];
LL dp[maxn][maxn];
int main(){
	read(n),read(m);
	init_mp();
	for(int i=1;i<=n;i++) read(w[i]);
	int u,v;
	for(int i=1;i<=m;i++){
		read(u),read(v);
		add_edge(u,v),add_edge(v,u);
	}
	queue<int> q;
	memset(dp,0x3f,sizeof(dp));
	for(int i=0;i<n;i++) dp[i][1]=1ll*i*w[1];
	for(int i=n-2;i>=0;i--){
		for(int j=1;j<=n;j++){
			for(int k=head[j];~k;k=nxt[k]){
				int v=e[k];
				dp[i][j]=min(dp[i][j],dp[i+1][v]+1ll*i*w[j]);
			}
		}
	}
	for(int i=1;i<=n;i++) printf("%lld\n",dp[0][i]);
	return 0;
}
//^o^
posted @ 2025-09-07 14:38  huangems  阅读(91)  评论(0)    收藏  举报