【2021江苏省省赛ACIJK题题解】

本文探讨了编程竞赛中的三个不同题目类型,包括模拟、分类讨论和推导公式。第一题涉及对联规则验证,第二题关注集合异或操作,第三题考察序列中连续1的最大值。每道题目都通过不同的思维和算法策略进行了解决,如模拟检查、分类讨论和数学推导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A (签到,模拟)
题目大意:给定形成对联的规则,判断两行字符串是否形成对联。

根据题目要求模拟即可。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

//head
const int N=1e4+10;
string s[N],t[N];
int n;
bool check()
{
	int a=s[n].size(),b=t[n].size();
	int x=s[n][a-1]-'0',y=t[n][b-1]-'0';
	if(x>=3&&x<=4&&y<=2) return 1;
	return 0;
}
void work()
{
	
	cin>>n;
	for(int i=1;i<=n;i++) cin>>s[i];
	for(int i=1;i<=n;i++) cin>>t[i];
	map<int,int> mp;
	
	if(!check()) cout<<"NO"<<endl;
	else {
		for(int i=1;i<=n;i++){
			int len=s[i].size();
			int y=s[i][len-1]-'0';
			if(y==3||y==4) y+=100;
			mp[i]=y;
		}
		for(int i=1;i<=n;i++){
			int len=t[i].size();
			int y=t[i][len-1]-'0';
			if(y==3||y==4) y+=100;
			if(abs(mp[i]-y)<=1) {
				cout<<"NO"<<endl;
				return ;
			}
		}
		cout<<"YES"<<endl;
	}
}
signed main()
{
	int t;
	cin>>t;
	while(t--) work();

	return 0;
}

I (思维,简单分类讨论)
题目大意:有一个包含0~ 2 m 2^m 2m-1的集合,从中选k个数,将k个数异或起来,保证其异或值为n. 问k最大可以是多少。

0~ 2 m 2^m 2m-1的所有数异或值为0(m>1),因此只需少异或上n这个数,即可让最终结果为n。注意m为1和n为0的情况。 简单分类讨论即可。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
//head
const int N=1e4+10;
int p[N];

map<int,int> mp;
void work()
{
	int m,n;
	cin>>m>>n;

	int ans=1LL<<m;
	if(m==1){
		if(n==0) cout<<1<<endl;
		else cout<<2<<endl;
	}
	else if(n==0) cout<<ans<<endl;
	else cout<<ans-1<<endl;
}
signed main()
{
	//ios;
	int t;
	cin>>t;
	while(t--) work();

	return 0;
}

K (规律,推公式)

题目大意:找到前缀长度为k的序列中,连续1的数量的最大值。

思路:可以把序列写的长一点,可以发现最长连续1的数量存在规律,把公式推出即可。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
//head
const int N=1e4+10;
int p[N];
int n;
map<int,int> mp;
void get()
{
	int x=1;
	for(int i=0;i<=32;i++){
		p[i]=x;
		x*=2;
	}
	int sum=0;
	mp[1]=1;
	for(int i=1;i<=32;i++){
		sum+=i*p[i-1];
		mp[sum]=i;
	}
}
void work()
{
	int n;
	cin>>n;
	if(n==1) {
		cout<<0<<endl;
		return ;
	}
	n--;
	int ans=0;
	for(auto x:mp){
		if(n>=x.first){
			ans=x.first;
			//cout<<ans<<'*'<<endl;
		}
	}
	if(n>=ans+1) cout<<mp[ans]+1<<endl;
	else cout<<mp[ans]<<endl;
}
signed main()
{
	//ios;
	int t;
	cin>>t;
	get();
	while(t--) work();

	return 0;
}

C (贪心,构造)

比较有意思的一个题,给定0~9每个数位的个数,要求构造出一个整数,满足:1.不含前导0。 2. 相邻位的数字不能相同。3. 构造出的整数的值尽可能小。若不存在输出-1 。

思路:一个很明显的性质是当数量最多的那个数字(假设为k个),大于剩余的所有数字之和(设为m), 即k>m时,无解。我们贪心的想,尽可能把较小的数字放在前面。 即我们从小到大枚举当前要放哪一个数字,若无法放置,则循环到下一个数字,若所有数字都无法放了,就说明无解。
注意一些细节问题。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
//head
const int N=1e5+10;
int cnt[N];

void work()
{
	int sum=0;
	int ma=0;
	for(int i=0;i<=9;i++){
		cin>>cnt[i];
		sum+=cnt[i];
		ma=max(ma,cnt[i]);
	}
	if(cnt[0]==1&&sum==1){
		cout<<0<<endl;
		return ;
	}
	int f=0;
	vector<int> ans;
	//cout<<ans.size()<<endl;
	while(sum)
	{
		for(int i=0;i<=9;i++){//枚举取哪个数
			
			if(i==0&&(int)ans.size()==0) continue;
			if(!cnt[i]||((int)ans.size()&&ans.back()==i)) continue;

			int x=0;
			for(int j=0;j<=9;j++){//求出哪个数剩余最多
				if(j==i){
					if(cnt[j]-1>cnt[x]) x=j;
				}
				else {
					if(cnt[j]>cnt[x]) x=j;
				}
			}
			int m=sum-cnt[x];
			if(x==i){
				if(cnt[x]-1<=m) {
					ans.push_back(i);
					sum--; cnt[i]--;
					f=1; break;
				}
			}
			else {
				if(cnt[x]<=m) {
					ans.push_back(i);
					sum--; cnt[i]--;
					f=1; break;
				}
			}
		}
		if(f==0){
			cout<<-1<<endl;
			return ;
		}
	}
	for(int i:ans) cout<<i;
	cout<<endl;

}
signed main()
{
	ios;
	int t;
	cin>>t;
	while(t--) work();

	return 0;
}

J (二分图染色,思维)

题目大意:给定一个n*m的矩阵,每个格子有个值,在不添加标记的情况下,相邻且值相同的格子将会被合并,若给一些格子添加标记后,则合并的条件是相邻,值相同,标记相同。问最少要添加几种标记,并且标记的数量最少,才能让每个格子都不会被合并。输出要添加标记的格子的坐标和其标记。

因为是相邻格子才会有可能被合并,因此可以发现最多两种标记即可,可把整个矩阵染成黑白两种颜色。在染色过程中看哪个颜色的格子的数量较少,将其添加到答案中去。

code:

#include<bits/stdc++.h>

using namespace std;
#define x first
#define y second
#define int long long
typedef pair<int,int> pii;
const int N=1e3+10;
int a[N][N];
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
bool st[N][N];
vector<pii> ans;

int n,m;
struct node{
	int x,y,c;
};

void bfs(int sx,int sy)
{
	vector<pii> v1,v2;
	queue<node> q;
	q.push({sx,sy,0});
	v1.push_back({sx,sy});
	st[sx][sy]=1;
	while(q.size())
	{
		auto t=q.front(); q.pop();
		for(int i=0;i<4;i++){
			int ex=t.x+dx[i],ey=t.y+dy[i];
			if(ex>n||ex<1||ey>m||ey<1||st[ex][ey]) continue;
			if(a[t.x][t.y]!=a[ex][ey]) continue;
			st[ex][ey]=1;
			if(t.c==0) v2.push_back({ex,ey});
			else v1.push_back({ex,ey});
			q.push({ex,ey,t.c^1});
		}
	}
	if(v1.size()<v2.size()){
		for(auto v:v1) ans.push_back(v);
	}
	else {
		for(auto v:v2) ans.push_back(v);
	}
}
void work()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) cin>>a[i][j];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!st[i][j]){
				bfs(i,j);
			}
		}
	}
	if(ans.size()==0) {
		cout<<"0 0"<<endl;
		return ;
	}
	cout<<1<<' '<<ans.size()<<endl;
	for(auto v:ans) cout<<v.x<<' '<<v.y<<' '<<1<<endl;
}
signed main()
{
	int t;
	t=1;//cin>>t;
	while(t--) work();
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值