目录
A题(简单签到)
题意:给n个数,每次选任意个数+1,最终让所有数相等,输出操作次数。
思路:显然找最大最小值相减就行
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define fo(x,a,b) for(int x=a;x<=b;x++)
#define of(x,a,b) for(int x=a;x>=b;x--)
#define close(); std::ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define PI acos(-1)
#define lowbit(a) ((a)&-(a))
#define lbit(a) (__builtin_ffsll(a))
#define ubit(a) (64-__builtin_clzll(a))
long long cnt;
long long mod=1e9+7;
long long INF=998244353;
long long wxd=1e18;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int qpow(int a,int b){
int ans=1;
while(b)
{
if(b%2==1) ans=ans*a%mod;//每部取模防止数据溢出
a=(a*a)%mod;//每部取模防止数据溢出
b=b/2;
}
return ans;
}
int A[60];
signed main()
{
close();
int T;
cin>>T;
while(T--){
int n;
cin>>n;
int maxx=0,minn=wxd;
fo(i,1,n){
cin>>A[i];
maxx=max(maxx,A[i]);
minn=min(minn,A[i]);
}
cout<<maxx-minn<<endl;
}
return 0;
}
B题(简单思维)
题意:是否存在一个正整数m让a/b/c乘以m 后让abc变成等差数列。
思路:由于abc顺序不可改变,那么分别算出满足等差数列的a1,b1,c1后,判断是否存在m能使a/b/c变为a1/b1/c1即可。(注意m为正整数)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define fo(x,a,b) for(int x=a;x<=b;x++)
#define of(x,a,b) for(int x=a;x>=b;x--)
#define close(); std::ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define PI acos(-1)
#define lowbit(a) ((a)&-(a))
#define lbit(a) (__builtin_ffsll(a))
#define ubit(a) (64-__builtin_clzll(a))
long long cnt;
long long mod=1e9+7;
long long INF=998244353;
long long wxd=1e18;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int qpow(int a,int b){
int ans=1;
while(b)
{
if(b%2==1) ans=ans*a%mod;//每部取模防止数据溢出
a=(a*a)%mod;//每部取模防止数据溢出
b=b/2;
}
return ans;
}
signed main()
{
close();
int T;
cin>>T;
while(T--){
int a,b,c;
cin>>a>>b>>c;
int d1=b-c,d2=a-b;
int a1=b+d1,c1=b-d2;//确定a1 c1
int gg=0;
if(a1>0&&a1%a==0)gg=1;// 判断是否存在m
if(c1>0&&c1%c==0)gg=1;
if((a+c)%2==0){ //确定 b1
int b1=(a+c)/2;
if(b1>0&&b1%b==0)gg=1;//判断是否存在m
}
if(gg==1)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
C题(简单思维)
题意:给定数组A,可以进行任意次操作将Ai变为⌊Ai/2⌋,最后让A变为1-n的排列。
思路:因为ai范围为1e9,最多2^32,那么最高O(32n)不会tle,那就可以输入后将ai处理为小于n的数,最后1-n遍历一遍看是否所有数都存在即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define fo(x,a,b) for(int x=a;x<=b;x++)
#define of(x,a,b) for(int x=a;x>=b;x--)
#define close(); std::ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define PI acos(-1)
#define lowbit(a) ((a)&-(a))
#define lbit(a) (__builtin_ffsll(a))
#define ubit(a) (64-__builtin_clzll(a))
long long cnt;
long long mod=1e9+7;
long long INF=998244353;
long long wxd=1e18;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int qpow(int a,int b){
int ans=1;
while(b)
{
if(b%2==1) ans=ans*a%mod;//每部取模防止数据溢出
a=(a*a)%mod;//每部取模防止数据溢出
b=b/2;
}
return ans;
}
int A[55];
int pd[55];
signed main()
{
close();
int T;
cin>>T;
while(T--){
int n;
cin>>n;
fo(i,1,n){
cin>>A[i];
while(A[i]>=1){
if(A[i]<=n&&!pd[A[i]]){ //将ai处理到小于n并记录
pd[A[i]]=1; //这里注意若一个数y能够通过除以2并向下取整得到 x
break; //那么x 通过除以2并向下取整得到的数 y也可以得到
} //所以顺序并不重要 只要处理到小于n就可以记录下了
A[i]/=2;
}
}
int gg=1;
fo(i,1,n){//判断是否1-n每个数都存在
if(!pd[i]){
gg=0;
break;
}
}
if(gg==1)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
fo(i,1,n)pd[i]=0;//初始化
}
return 0;
}
D题(二分/贪心)
题意:给定字符串s,数字k,将字符串s分为k组(s可以不全分完但必须存在k组),k中元素可以任意两两交换 ,最终满足k组字符串皆为回文串且最短串最长。
思路:首先“最小值最大”很明显的二分,但如果运用一点小思维,三行计算O(1)就可以了。涂色的可以任意交换这个条件意味着回文串就变成了任意两个相同的字母(或加上一个单个字母)即可构成回文串,那么我们只需要将字母个数记录,两两一组,记录下组数和剩余的单个字母个数即可通过公式求得答案。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define fo(x,a,b) for(int x=a;x<=b;x++)
#define of(x,a,b) for(int x=a;x>=b;x--)
#define close(); std::ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define PI acos(-1)
#define lowbit(a) ((a)&-(a))
#define lbit(a) (__builtin_ffsll(a))
#define ubit(a) (64-__builtin_clzll(a))
long long cnt;
long long mod=1e9+7;
long long INF=998244353;
long long wxd=1e18;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int qpow(int a,int b){
int ans=1;
while(b)
{
if(b%2==1) ans=ans*a%mod;//每部取模防止数据溢出
a=(a*a)%mod;//每部取模防止数据溢出
b=b/2;
}
return ans;
}
map<char,int>mp;
signed main()
{
close();
int T;
cin>>T;
while(T--){
int n,k;
cin>>n>>k;
fo(i,1,26)mp['a'+i-1]=0;//初始化map
string s;
cin>>s;
fo(i,0,s.size()-1){
mp[s[i]]++; //记录字母个数
}
int zu=0,ge=0;
fo(i,1,26){
zu+=mp['a'+i-1]/2;//计算出组数和单独个数
ge+=mp['a'+i-1]%2;
}
int ans=(zu/k)*2; //首先将“组”均分到k种颜色
int g=zu%k; //记录下剩余的“组”数
if(g==0&&ge>=k)ans+=1; //若“组”正好分完且“个”数能分到每种颜色中 最小值+1
else if(g*2+ge>=k)ans+=1;//将“组”拆成单个加上“个”能分到每种颜色中 最小值+1
cout<<ans<<endl;
}
return 0;
}
F题(二分)
题意:给定一个n。确定一个x满足[1,n) 。查询+ m使x=x+m并返回⌊x/n⌋,在能确定x值时输出!x(x为变化后的值)。
思路:首先交互题cout一定要加endl!
简单分析题意发现是一个猜数字的游戏,且限制了访问次数为10次,发现n范围为1000,而2^10是1024,那么很明显,这是个二分找数字。
返回值为⌊x/n⌋向下取整,那么我们的查询一定就是加上某个数是否会让⌊x/n⌋向下取整变化有关了,所以我们对当前情况的x%n的部分二分,去判断这个部分会不会大于n就好了。
那么我们将二分分为两种状态,一种是x%n的部分在0到r,另一种是x%n的部分在l到n-1。
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define endl '\n'
#define fo(x,a,b) for(int x=a;x<=b;x++)
#define of(x,a,b) for(int x=a;x>=b;x--)
#define close(); std::ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define PI acos(-1)
#define lowbit(a) ((a)&-(a))
#define lbit(a) (__builtin_ffsll(a))
#define ubit(a) (64-__builtin_clzll(a))
long long cnt;
long long mod=1e9+7;
long long INF=998244353;
long long wxd=1e18;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int qpow(int a,int b){
int ans=1;
while(b)
{
if(b%2==1) ans=ans*a%mod;//每部取模防止数据溢出
a=(a*a)%mod;//每部取模防止数据溢出
b=b/2;
}
return ans;
}
signed main()
{
close();
int n;
cin>>n;
int zhuangt; //状态1 前半段 状态2 后半段
int bei=0; //n的倍数 bei为0
int l=1,r=n-1,ans;
int mid=(l+r)/2;
cout<<"+ "<<mid<<endl; //初始输出中间值确定状态
int x;
cin>>x;
if(x==0){
zhuangt=2;
if(n%2==1)l=mid;
else l=mid+1;
r=n-1;
}
else{
bei=1;
zhuangt=1;
l=0;
r=mid-1;
}
while(1){
if(l==r){ //若二分lr相等即为找到确定值
cout<<"! "<<l+bei*n<<endl;
break;
}
if(zhuangt==1){
mid=(l+r)/2+(l+r)%2; //这里避免l=0,r=1时mid为0
cout<<"+ "<<n-mid<<endl;//查询范围是1到n-1 所以mid不可为0
cin>>x;
if(x==bei){
zhuangt=2;
l=l+n-mid;
r=n-1;
}
else{
bei=x;
zhuangt=1;
l=0;
r=r-mid;
}
}
else{
mid=(n-l+n-r)/2;
cout<<"+ "<<mid<<endl;
cin>>x;
if(x==bei){
zhuangt=2;
if((n-l+n-r)%2==1)l=l+mid; //强化l范围变化可以缩短l r范围
else l=l+mid-1;
r=n-1;
}
else{
bei=x;
zhuangt=1;
l=0;
r=mid-1;
}
}
}
return 0;
}