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\)
整理可以得到
当上式成立时,满足题意
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;
}