题解(A~D):Codeforces Round #749 (Div. 1 + Div. 2, based on Technocup 2022 Elimination Round 1)

话不多说,看题解:

A. Windblume OdeCF1583A)**

**分析:**题意大概是:给一个序列,找一个最大的子序列,使序列的和为合数。首先应该考虑的是原序列本身,若该序列的和为合数则答案显然就是原序列。若和为质数,则和必为奇数(因为n>=3):
注意a是互不相同的,若n个数全为偶数,则合也应该是偶数,矛盾。
于是n个数中有一个奇数,去掉该奇数剩余的数是偶数而且大于2(因为n>=3),因此必存在一个长为n-1的子序列和为合数。

代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int a[220];
bool check(int x){
	for(int i=2;i*i<=x;i++){
		if(x%i==0) return 0;
	}
	return 1;
}
void solve(){
	int n;cin>>n;
	int s=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s+=a[i];
	}
	if(!check(s))
	{
		cout<<n<<endl;
		for(int i=1;i<=n;i++) cout<<i<<" \n"[i==n];
	}
	else
	{
		cout<<n-1<<endl;
		for(int i=1;i<=n;i++){
			if(a[i]%2)
			{
				for(int j=1;j<=n;j++)
				if(j!=i)cout<<j<<" ";
				cout<<endl;
				return;
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--){
		solve();	
	} 
	return 0;
}

B. Omkar and Heavenly TreeCF1583B
分析:题意:给出一些树上的限制条件,点B不在点A和点C的最短路上,让你构造一颗符合条件的树。
这里考查了一种很常见的图(星图)
一个简单的星图
由于限制数不超过n-1,因此至少有一个点是没有“不在路径上”这个限制的,找出一个这种点,以他为中心建一个星图就好了。

代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int n,m;
int vis[100010];
void solve(){
	int a,b,c;
	cin>>n>>m;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=m;i++){
		cin>>a>>b>>c;
		vis[b]=1;
	}
	int ans;
	for(int i=1;i<=n;i++){
		if(!vis[i])
		{
			ans=i;
			break;
		}
	}
	for(int i=1;i<=n;i++){
		if(i!=ans)
		{
			cout<<ans<<" "<<i<<endl;
		}
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--){
		solve();	
	} 
	return 0;
}

C. Omkar and Determination(CF1583C

分析:有若干次询问,每次询问的意思是:
将x1~x2列之间的列取出来,得到一个新的图。新的图哪些点可以走出去是很容易求的。若只告诉你哪些点可以走出去,你能将这个新图换原出来吗?(注意每次询问是独立的,不会改变原图)
很显然,在新图中,如果一个点的上面和左面都是X,那么这个点是走不出去的,无论它本身是不是X,于是乎这个点就变得不确定了,这个点不确定之后这一列就不确定了,这一列不确定那么整个子图就不确定了。反之,没如果这样的点,那么每个点就都能根据它左边和上边的点来确定自己的状态,于是所有的点都确定了。于是问题变成了,x1~x2(不包括x1,因为x1是左边界,它的左边没有叉)中有没有某一列含有不确定点?
我们可以预处理出所有不确定点,进而得到不确定列,然后用前缀和回答询问。

代码

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

vector<vector<int> >mp1,mp2;
int a[1000010],s[1000010];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,m;
	cin>>n>>m;
	mp1.resize(n+5); 
	mp2.resize(n+5);
	char ch;
	for(int i=1;i<=n;i++){
		mp1[i].resize(m+5);
		mp2[i].resize(m+5);
		for(int j=1;j<=m;j++){
			cin>>ch;
			mp1[i][j]=ch=='.'?0:1;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			mp2[i][j]=0;
			if(i!=1&&j!=1)
			{
				if(mp1[i-1][j]==1&&mp1[i][j-1]==1)
				{
					mp2[i][j]=1;
					a[j]=1;
				}
			}
		}
	}
	for(int i=1;i<=m;i++){
		s[i]=s[i-1]+a[i];
	}
	int q;cin>>q;
	while(q--){
		int l,r;cin>>l>>r;
		if(s[r]-s[l]) cout<<"NO"<<endl;
		else cout<<"YES"<<endl;
	} 
	return 0;
}

D. Omkar and the Meaning of LifeCF1583D
**分析:**理解题意不难,我直接说思路和解法吧:
可以询问2n次,我们可以考虑对 n 位每位询问两次。一种比较简单的询问数列是1 1 1 1 2 1 1 1 ,也就是第 i 位是2,其他的都是1。这有什么用呢?如果得到的 s 序列有两个数相同,那么有一个一定是第 i 位,这相当于第 i 位加 1以后得到了另一位。如果 k!=i,那么这一位就是 k。因此,通过这种询问我们可以得到某一位的后一位是谁,从对称的角度我们也能得到每一位的前一位是谁,这样答案就出来了。

代码:

#include<bits/stdc++.h>
using namespace std;

int nxt[110],pre[110],a[110];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n;cin>>n;
	for(int i=n;i>=1;i--){
		int g;
		cout<<"? ";
		for(int j=1;j<=n;j++){
			if(j==i) cout<<1;
			else cout<<2;
			if(j!=n) cout<<" "; 
		}
		cout<<endl;
		cout.flush();
		cin>>g;
		if(g!=0&&g!=i)
		{
			pre[i]=g;
			nxt[g]=i;
		}
		cout<<"? ";
		for(int j=1;j<=n;j++){
			if(j==i) cout<<2;
			else cout<<1;
			if(j!=n) cout<<" ";
		}
		cout<<endl;
		cout.flush();
		cin>>g;
		if(g!=0&&g!=i)
		{
			nxt[i]=g;
			pre[g]=i;
		}
	}
	int ans;
	for(int i=1;i<=n;i++)
	{
		if(pre[i]==0)
		{
			ans=i;
			break;
		}	
	} 
	cout<<"! ";
	for(int i=1;i<=n;i++)
	{
		a[ans]=i;
		ans=nxt[ans];
	}
	for(int i=1;i<=n;i++)
	{
		cout<<a[i];
		if(i!=n) cout<<" ";
	}
	cout<<endl;
	cout.flush();
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

组合,我有特殊的计数技巧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值