A. Divide and Conque
如果原本sum是偶数不操作,如果原本是奇数,则对于 a1....an 计算每个数从奇数变成偶数或者从偶数变成奇数需要的最少次数 pi , 对p取min即可
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 1e5+10;
ll a[maxn];
ll times[maxn];
void solve(){
int n;cin>>n;
for(int i = 1;i<=n;i++)
cin>>a[i];
ll sum = 0;
for(int i = 1;i<=n;i++)
sum+=a[i];
if(sum%2==0){
cout<<0<<endl;
return;
}
int mi = 1e9;
for(int i = 1;i<=n;i++){
int j = a[i]%2;
int ss = 0;
while(a[i]%2==j){
ss++;
a[i]/=2;
}
mi = min(ss,mi);
}
cout<<mi<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
B. Make Array Good
根据题意可知,如果要所有数满足条件,则最终的数列a排序完应该满足条件: ai=ai−1∗c(c>=1) ,那么很自然我们直接进行排序然后以最小的数为a1,后面的数依次操作变成最近的满足条件的数就好。
同时易证,每次操作最多一次
- ai=ai−1 ,不用操作
- ai<ai−1 ,从 a1 开始考虑,由于 a2>a1 ,如果 a2 要变成 a1 的倍数,那直接变成 ca1(c>=1) 即可,同时操作的范围不会超过 自然不会超过本身a1,自然不会超过a2本身
- ai>ai−1 ,直接变成 ai−1 的两倍就好了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 1e5+10;
ll a[maxn];
pair<int,int>p[maxn];
void solve(){
int n;cin>>n;
for(int i = 1;i<=n;i++)
cin>>a[i];
for(int i =1;i<=n;i++){
p[i] = {a[i],i};
}
sort(p+1,p+n+1);
int now = p[1].first;
vector<pair<int,int>>ans;
for(int i = 2;i<=n;i++){
if(p[i].first==now)
continue;
else{
if(p[i].first%now==0){
now = p[i].first;
}
else if(now>p[i].first){
ans.push_back({p[i].second, now-p[i].first});
}
else{
int pre =(p[i].first/now+1)*now;
ans.push_back({p[i].second, pre - p[i].first});
now = pre;
}
}
//cout<<now<<" "<<i<<endl;
}
int len = ans.size();
cout<<len<<endl;
for(auto j:ans)
cout<<j.first<<" "<<j.second<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
C. Binary Strings are Fun
题意很绕,大概就是说对于一串二进制01字符串s(下标从1开始)而言,截取每个开头到奇数下标的范围 s[1..i] 子字符串s1,s1中的median(字符串中最多的那个字符)要位于所有奇数下标上。这样的字符串是good的
然后对于一个字符串s而言,他有一个拓展串s2概念,指的是s2中的奇数下标2k-1分别对应s中的k下标。
问你,对于一个字符串s,其子串 s[1..i] 的good拓展串之和
我们可以发现,对于一个字符串0110而言,其拓展串想good只能0 1 1 0 1 0 0这样填入,在两个1中间如果填1则最后的0是就不满足了,也就是说事实上只有在尾部的连续0串或者1串间我们才能随意放入数字。
那我们遍历过去顺便统计一下尾部连续的长度,统计和即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 1e5+10;
const int mod = 998244353;
ll a[maxn];
pair<int,int>p[maxn];
//奇数长度二进制串
//到i为之最多的i就是median,要每个奇数位都是median
long long qpow(long long base, long long power) {
long long result = 1;
while (power > 0) {
if (power & 1) {//此处等价于if(power%2==1)
result = result * base % mod;
}
power >>= 1;//此处等价于power=power/2
base = (base * base) % mod;
}
return result;
}
void solve(){
int n;cin>>n;
string s;cin>>s;
if(n==1){
cout<<1<<endl;
return;
}
s = '?'+s;
int len = 1;
char now = s[1];
ll ans = 1;
for(int i = 2;i<=n;i++){
if(now==s[i]){
len++;
}
else{
now = s[i];
len = 1;
}
ll pre = 1;
pre*= qpow(2,len-1);
pre%=mod;
ans = (ans+pre)%mod;
//cout<<i<<" "<<ans<<endl;
}
cout<<ans<<endl;
}
//如果最后有连续的1或者0,那么从那一段开始我们可以随意选任意的1或者0,除外我们必须填唯一
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
D. GCD Queries
交互题,我们可以发现一个性质, gcd(a,b)<=min(a,b) ,但当a或者b有0时, gcd(a,b)<=max(a,b)
由于是一个purmutation,对于abc三个数,只要有一个0在abc中,那么我们最后留下的一定是0和一个较大的数,这样一来,我们一定能保证0在x和y中。
#include <bits/stdc++.h>
using namespace std;
int ask(int i, int j) {
cout << "? " << i << " " << j << endl;
int t; cin >> t; return t;
}
int ans(int i, int j) {
cout << "! " << i << " " << j << endl;
int t; cin >> t; return t;
}
void solve() {
int n;
cin >> n;
int x = 1, y = 2;
int now = ask(x, y);
for(int i = 3; i <= n; i ++) {
int s = ask(x, i), t = ask(y, i);
int xx = x, yy = y;
if(s > now) {
xx = x, yy = i;
now = s;
}
if(t > now) {
xx = y, yy = i;
now = t;
}
x = xx, y = yy;
}
ans(x, y);
}
int main() {
int tc;
cin >> tc;
for(; tc; tc --) solve();
}