CF补题 1004-Div.2

CF补题 1004-Div.2-20250309

https://codeforces.com/contest/2067

A:
题目大意:给出 \(x,y\) ,判断是否存在一个 \(n\) 满足 \(n\) 的数位和为 \(n\) ,加 \(1\) 后数位和为 \(y\)

#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
 
using namespace std;

void solve(void){
	int x,y;
	cin>>x>>y;
	if (y>x+1){
		cout<<"No"<<endl;
		return;
	}
	if ((x-y+1)%9) cout<<"No"<<endl;
	else cout<<"Yes"<<endl;
}

int main()
{
	Trd;
	
	return 0;
}

显然考虑极端情况,\(n+1\) 的数位和一定不会大于 \(n\) 的数位和 \(+1\)

如果个位上是 \(9\) ,使 \(n+1\) 后的数位和等价于 \(n\) 的数位和 \(-9+1\)

同理,如果十位也是 \(9\) ,那么 \(n+1\) 的数位和等于 \(n\) 的数位和 \(-9-9+1\)

整理可以得到

\[x-k*9+1=y \]

当上式成立时,满足题意

B:
题目大意:存在两个集合,一开始第一个集合中有 \(n\) 个数字(\(n\) 为偶数),第二个集合为空,每次可以进行两种操作

  • 从第一个集合中选择任意一个数字并将其移动到第二个集合中
  • 从第一个集合中选择一个第二个集合中也有的数字,将其数值加上 \(1\)

判断能否使这两个集合完全相等

#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
 
using namespace std;

void solve(void){
	int n;
	cin>>n;
	map<int,int> mp;
	for (int i=1;i<=n;i++){
		int t;
		cin>>t;
		mp[t]++;
	}
	for (auto [k,v]:mp){
		if (v==1){
			cout<<"No"<<endl;
			return;
		}
		if (v>2){
			mp[k+1]+=v-2;
			mp[k]-=v-2;
		}
	}
	cout<<"Yes"<<endl;
	
}


int main()
{
	Trd;
	
	return 0;
}

如果一个数字有且仅有一个,那么这两个集合一定不会相等

所以一个数字至少需要两个,如果多出来,那么可以考虑向上合成

读入数据后,存进 map

从小到大排序后,开始枚举每个数字的个数情况,如果这个数字只有一个,集合一定不会相同

如果这个数字的个数等于 \(2\),那么向上合成出 \(+1\) 后的数字

可以证明,向上合成一定不会使集合为劣

C:

题目大意:给定 \(x\) ,可以使 \(x\) 加上 \(k\) 个数位全为 \(9\) 的数,判断能使 \(x\) 上数位有 \(7\)\(k\) 的最小值

#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
 
using namespace std;

int judge(LL b,LL x){
	for (int i=1;i<10;i++){
		LL dx=x+i*b;
		while (dx){
			if (dx%10==7)
				return i;
			dx/=10;
		}
	}
}

void solve(void){
	string s;
	cin>>s;
	LL x=0;
	for (int i=0;i<s.size();i++){
		if (s[i]=='7'){
			cout<<0<<endl;
			return;
		}
		x=x*10+s[i]-'0';
	}
	
	LL b=0;
	int ans=15;
	
	for (int i=1;i<=s.size();i++){
		b=b*10+9;
		ans=min(ans,judge(b,x));
	}
	cout<<ans<<endl;
	
}

int main()
{
	Trd;
	
	return 0;
}

对于任意一个数,其加上 \(k\) 个数位全为 \(9\) 的数,满足题意的 \(k\) 一定不会超过 \(9\)

所以枚举数位全为 \(9\) 的数,并且第二重枚举 \(k\) 的数量

for (int i=0;i<s.size();i++){
	if (s[i]=='7'){//如果原本含有7,直接输出0
		cout<<0<<endl;
		return;
	}
	x=x*10+s[i]-'0';//字符串转换整数
}

定义 b 表示数位全为 \(9\) 的数

for (int i=1;i<=s.size();i++){//x有s.size()-1位,那么k最多也只有s.size()位9
	b=b*10+9;//每次循环递增b,保持9,99,999...
	ans=min(ans,judge(b,x));
}

judge 函数判断当前的 b 需要加多少次才能满足题意

int judge(LL b,LL x){
	for (int i=1;i<10;i++){//从小到大枚举需要加的次数
		LL dx=x+i*b;//计算x+kb
		while (dx){//判断是否含有7
			if (dx%10==7)
				return i;//如果有7立即返回加的次数
			dx/=10;
		}
	}
}

D:

题目大意:有一个从 \([1,n]\) 的整数组成的数组 \(x_1,x_2,\cdots,x_n\),另外还存在一个隐藏的数组 \(y_1,y_2,\cdots,y_n\ \ y_i\in[1,n]\)

已知对于所有的 \(i\in[1,n]\) 都满足 \(x_i\ne y_i,(x_i,y_i)\ne(x_j,y_j)\),对于 \(x,y\) 的关系,有两种假设:

  • A:一个 \(n\) 个顶点的有向图,编号 \([1,n]\) ,有 \(n\) 条表示为 \(x_i\to y_i\) 的有向边

  • B:平面上的 \(n\) 个点,其中 \(i\) 的坐标为 \((x_i,y_i)\)

有两次询问机会,请确定 \(x,y\) 的关系,每次询问都会得到

  • A:顶点 \(i,j\) 的最短路径长度,如果不连通返回 \(0\)
  • B:点 \(i,j\) 之间的曼哈顿距离即 \(\lvert x_i-x_j\rvert+_\lvert y_i-y_j\rvert\)
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
 
using namespace std;

void solve(void){
	int n;
	cin>>n;
	vector<int> x(n+10);
	map<int,int> mp;
	bool f=0;
	for (int i=1;i<=n;i++){
		cin>>x[i];
		mp[x[i]]++;
		if (mp[x[i]]>1) f=1;
	}
	if (f==1){
		for (int i=1;i<=n;i++){
			if (mp[i]==0){
				int ans;
				cout<<'?'<<' '<<i<<' '<<x[1]<<endl;
				cin>>ans;
				if (ans==0) cout<<'!'<<' '<<'A'<<endl;
				else cout<<'!'<<' '<<'B'<<endl;
				return;
			}
		}
	}else{
		int ii,jj;
		for (int i=1;i<=n;i++){
			if (x[i]==1) ii=i;
			if (x[i]==n) jj=i;
		}
		int a,b;
		cout<<'?'<<' '<<ii<<' '<<jj<<endl;
		cin>>a;
		cout<<'?'<<' '<<jj<<' '<<ii<<endl;
		cin>>b;
		if (a!=b) cout<<'!'<<' '<<'A'<<endl;
		else{
			if (a<n-1) cout<<'!'<<' '<<'A'<<endl;
			else cout<<'!'<<' '<<'B'<<endl;
		}
		return;
	}
}

int main()
{
	cintie;
	Trd;
	
	return 0;
}

分别考虑 A,B 的性质:

  • A:如果 \(i\to j\) 的路径存在,那么路径长度 \(\in[1,n-1]\)

  • B:询问 \((i,j)\)\((j,i)\) 的回答必然相同

当数组 \(x\) 不包含 \([1,n]\) 的所有数时,可以询问一个不存在的 $k\notin {x_1,x_2,\cdots,x_n},k\in[1,n] $ ,与任意一个 \(r\)

如果答案为 \(0\) ,符合 A,因为不存在 \(x_k\to y_k\) 的路径,否则符合 B

当数组 \(x\) 包含 \([1,n]\) 的所有数时,即 \(x\)\([1,n]\) 的全排列

可以询问 \(ii,jj\) ,满足 \(x_{ii}=1,x_{jj}=n\) ,这样的话,如果收到的两次回答不同,那么绝对为 A
收到的两次回答相同的话,则需要判断答案所在的范围

A:\(dis\in[1,n-1]\) 、B:\(\lvert x_i-x_j\rvert+\lvert y_i-y_j\rvert \ge n-1\)

\(n\ge3\) 时,若为 A ,且两次回答的 \(dis\) 相同,那么它们必然不能都取到 \(n-1\)

所以,判断答案是否小于 \(n-1\) 即可唯一确定

if (a!=b) cout<<'!'<<' '<<'A'<<endl;
else{
	if (a<n-1) cout<<'!'<<' '<<'A'<<endl;
	else cout<<'!'<<' '<<'B'<<endl;
}
posted @ 2025-03-12 18:37  才瓯  阅读(8)  评论(0)    收藏  举报