A 题目链接:Problem - A - Codeforces
input:
4
4
1 1 1 1
2
7 4
3
1 2 4
1
15
output:
0
2
1
4
题意:
现给出一个定义:如果一个数组所有元素的和是偶数,则称该数组为 good 。
给定长度为 n 的数组 a ,给定一种操作:任选数组 a 中的一个元素,将其除以2(下取整),问最少操作多少次,可以使数组 a 为 good。
思路:
数组中奇数的个数会影响总和的结果:
1.如果奇数个数为偶,那么不需要任何操作,数组 a 即为 good,直接输出0即可。
2.如果奇数个数为奇,那么需要将奇数个数变为偶。有两种方案,一是令某个奇数变为偶数,二是令某个偶数变为奇数。由于 n 很小,所以说直接遍历数组,维护每个元素奇偶性改变所需要的最小操作次数的最小值即可。
代码如下:
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2e5+10;
int t,n;
int a[N];
bool vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
vis[i]=0;
if(a[i]&1)
{
cnt++;
vis[i]=1;
}
}
if(cnt%2==0)
{
cout<<0<<endl;
continue;
}
int ans=10000;
for(int i=1;i<=n;i++)
{
int k=0;
if(vis[i])
{
while(a[i]%2==1)
{
a[i]/=2;
++k;
}
ans=min(ans,k);
}
else
{
while(a[i]%2==0)
{
a[i]/=2;
++k;
}
ans=min(ans,k);
}
}
cout<<ans<<endl;
}
return 0;
}
B 题目链接:Problem - B - Codeforces
input:
4
4
2 3 5 5
2
4 8
5
3 4 343 5 6
3
31 5 17
output:
4
1 2
1 1
2 2
3 0
0
5
1 3
1 4
2 1
5 4
3 7
3
1 29
2 5
3 3
题意:
现给出一个定义:如果一个数组 a 的所有元素对 ai , aj 满足 max(ai , aj) 可以被 min(ai , aj) 整除,则称该数组为 good 。
给定长度为 n 的数组 a ,给定一种操作:任选 a 中的一个元素,令其加上不大于自身的任意自然数 x ,并保证元素修改后的值不大于1e18。试对数组 a 进行修改,使其为 good ,并保证操作次数不大于 n 次。
思路:
直接对数组 a 从小到大排序,以最小元素的两倍为基准,将其后不大于基准值的元素全部构造为基准值,若当前元素已经大于该元素的两倍,将基准值不断乘2,直至基准值大于当前元素,然后构造,依次类推,注意计数并离线处理答案。
代码如下:
#pragma GCC optimize(3)
#include<bits/stdc++.h>
//#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int mod=1e9+7;
const int N=2e5+10;
int t,n;
struct node{
ll v;
int id;
}a[N];
bool cmp(node a,node b)
{
return a.v<b.v;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].v;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
ll cur=a[1].v;
vector<PII> vec;
for(int i=2;i<=n;i++)
{
while(a[i].v>cur*2)
{
cur*=2;
}
if(a[i].v<cur*2)
{
vec.push_back({a[i].id,cur*2-a[i].v});
}
else if(a[i].v==cur*2)
{
continue;
}
}
cout<<vec.size()<<endl;
for(int i=0;i<vec.size();i++)
{
cout<<vec[i].first<<" "<<vec[i].second<<endl;
}
}
return 0;
}
C 题目链接:Problem - C - Codeforces
input:
6
1
1
1
0
2
11
3
010
9
101101111
37
1011011111011010000011011111111011111
output:
1
1
3
3
21
365
题意:
现给出一个定义:对于长度为奇数01串 b ,如果对于每一个奇数位的前缀,都满足该前缀的中位数即为该前缀的最后一位,那么称数组 b 为 good(01串的中位数即为众数)。
对于一个长度为 k 的01串,定义其 extension:长度为 2k - 1 的01串,第 2i - 1 位是原串的第 i 位,构造方式有2^(k-1)种(可以理解为长度k的串,两两字符之间共 k - 1 个空,每个空可以插入0或1)。
给定长度为 n 的01串 s ,试求出该串的所有前缀的所有满足 good 的扩展方案总和(有点绕,大致就是这个意思,如果不能很好理解我的翻译,可以看原题面)。
思路:
明显递推。推了一会儿状态转移,只推出了当前位和前一位相等的状态转移方程,看了一下样例,直接根据样例猜的当前位和前一位不相等的状态转移:
1.当前位和前一位相等,则当前前缀的目标方案数是前一位的前缀的目标方案数的两倍
2.当前位和前一位不等,则当前前缀的目标方案数为1
代码如下:
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=2e5+10;
int t,n;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
string s;
cin>>s;
s=" "+s;
int cur=1;
int ans=1;
for(int i=2;i<=n;i++)
{
if(s[i]!=s[i-1])
{
cur=1;
ans=(ans+1)%mod;
}
else
{
cur=(cur*2)%mod;
ans=(ans+cur)%mod;
}
}
cout<<ans<<endl;
}
return 0;
}
D 题目链接:Problem - D - Codeforces
input:
2
2
1
1
5
2
4
1
output:
? 1 2
! 1 2
? 1 2
? 2 3
! 3 3
题意:
交互题。
给定一个数 n ,评测方有一个长度为 n 的排列 p(由 0 ~ n - 1 组成,询问方看不到该排列)。现在可以向评测方提出不超过 2n 次询问,询问格式为:"? i j",评测方会给出一个数,代表 gcd( pi , pj)。所有询问结束后,询问方需提供两个下标,意为数字 0 在两个下标之一上,提供格式为:"! x y"
提供答案结束后,评测放会返回 1 或 -1,询问方须接收这个返回。1代表答案正确,-1代表答案错误,程序返回 wrong answer。
注意:gcd(0 , x) == x (这个很重要!!!)
思路:
某一个非0值与 0 gcd,得到的是该数本身,并且该数与其余任何数的 gcd 都不可能超过该数本身。所以0和其余数 gcd 得到的值是这个数通过 gcd 能得到的值里最大的。因此我们令 x = 1 , y = 2,从下标3开始往后遍历,每次遍历询问两次: x, i 和 y , i,设得到的两个结果分别为 a 和 b 。分以下三种情况讨论:
1. a == b,说明当前 pi 一定不是 0 ,因为0和两个不同的数 gcd 一定是得到不同的值,所以直接跳过,不做任何操作,继续遍历
2. a > b,我们维护 gcd 较大的情况,令 y = i ,继续遍历
3. a < b,意义同上,令 x = i ,继续遍历
遍历结束后提供 x 和 y 即可。
代码如下:
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2e5+10;
int t,n,x,y,a,b;
int main()
{
cin>>t;
while(t--)
{
cin>>n;
x=1,y=2;
for(int i=3;i<=n;i++)
{
cout<<"? "<<x<<" "<<i<<endl;
cin>>a;
cout<<"? "<<y<<" "<<i<<endl;
cin>>b;
if(a==b)
continue;
else if(a>b)
y=i;
else
x=i;
}
int k;
cout<<"! "<<x<<" "<<y<<endl;
cin>>k;
}
return 0;
}