Codeforces Round #838 (Div. 2) A-D

Codeforces Round #838 (Div. 2) A-D

A. Divide and Conquer

题解:

题意为给你n个数,要使n个数的和变为偶数,一次操作可以令a_{i}=\left \lfloor a_{i}/2 \right \rfloor,求最少让n个数的和为偶数的操作次数。

若初始状态n个数的和sum为偶数,则无需再操作,否则,此时sum为奇数,每次进行一次操作的话,sum会减去\left \lceil a_{i}/2 \right \rceil,若\left \lceil a_{i}/2 \right \rceil为奇数的话,sum便会变为偶数。对于每个数a_{i}

a_{i}为偶数,则每次进行/2的操作,寻找a_{i}变为奇数的情况的操作次数,即sum减去奇数的操作次数。

a_{i}为奇数,则每次进行/2的操作,寻找a_{i}变为偶数的情况(变为0)的操作次数,即sum减去奇数的操作次数。

然后对所有a_{i}的操作次数进行比较,答案为最小值

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6;
int a[N],b[N],n,m,x,y,z,t,k,q;
int ans,res;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
    {
        cin>>n;
        int sum=0;
        for(int i=1; i<=n; i++)
        {
            cin>>a[i];
            sum+=a[i];
        }
        if(sum%2==0)
        {
            cout<<0<<"\n";
            continue;
        }
        int ans=1e9;
        for(int i=1; i<=n; i++)
        {
            int res = 0;
            if(a[i] % 2 == 0)
            {
                while(a[i] % 2 == 0)
                {
                    res ++;
                    a[i] /= 2;
                }
            }
            else 
            {
                while(a[i] & 1)
                {
                    a[i] /= 2;
                    res ++;
                }
            }
            ans = min(ans, res);
        }
        cout<<ans<<"\n";
    }
    return 0;
}

 B. Make Array Good

 题解:

题意为给你n个数,要求使任意两个i,j,(1<=i,j<=n),使min(a_{i},a_{j}) | max(a_{i},a_{j})

即任意两个数中最大值能够整除最小值,一次操作能够使a_{i}\rightarrow a_{i}+x ,(0<=x<=a_{i})

求操作次数和每次操作的过程,需要保证操作次数在n次以内。

先排序,然后从第二个开始依次检查是否是前一个的倍数,若不是倍数,则令a_{i}\rightarrow a_{i}+a_{i-1} -a_{i}%a_{i-1},然后此时的a_{i}一定变为a_{i-1}的倍数,依次操作,

最终这个n个数一定满足上述条件。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6;
int n,m,x,y,z,t,k,q;
int ans,res;
struct MM
{
    int a,b;
};
bool cmp(MM aa,MM bb)
{
    return aa.a<bb.a;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
    {
        cin>>n;
        int sum=0;
        MM xy[n+10];
        for(int i=1; i<=n; i++)
        {
            cin>>xy[i].a;
            xy[i].b=i;
        }
        sort(xy+1,xy+n+1,cmp);
        vector<pair<int,int> >v;
        for(int i=2;i<=n;i++)
        {
            if(xy[i].a%xy[i-1].a==0)
                continue;
            v.push_back({xy[i].b,xy[i-1].a-xy[i].a%xy[i-1].a});
            xy[i].a+=xy[i-1].a-xy[i].a%xy[i-1].a;
        }
        cout<<v.size()<<"\n";
        for(auto [x,y]:v)
        {
            cout<<x<<" "<<y<<"\n";
        }
    }
    return 0;
}

 C. Binary Strings are Fun

题意:

给你长度为n的01字符串,求他的每个前缀串的“扩展良好串”的个数,

“扩展良好串”意思是对原串a,扩展串b来说,a_{i}=b_{2*i-1}

且对于每个奇数i,b_{i}等于前i个数的中位数(中位数是前i个数拍好序之后中间的那个数)

观察得到,当i为奇数时,每个b_{i}都固定了,则现在需要求解i等于偶数的时候能填的情况,

当i为奇数时,若b_{i}=b_{i+2}时,即前i个数的中位数为b_{i},且前i+2个数的中位数也为b_{i},现考虑

b_{i+1}填什么,发现无论b_{i+1}填什么,因为b_{i}=b_{i+2},则保证前i+2个数的中位数一定为b_{i} ,

此时b_{i+1}可填0或1,有两种情况。

 若b_{i}\neq b_{i+2}时,即前i个数的中位数为b_{i},且前i+2个数的中位数为(b_{i}+1)%2,现考虑

b_{i+1}填什么,发现只有b_{i+1}=b_{i+2}时,才能保证前i+2个数的中位数为(b_{i}+1)%2

则此时b_{i+1}=b_{i+2},只有一种情况。

综上,依次计算字符串前缀和能组成的字符串即可

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6;
int n,m,x,y,z,t,k,q;
int ans,res;
string s;
typedef long long ll;
const ll MOD=998244353;
ll quickpow(ll a,ll b)
{
    ll sum=1;
    while(b)
    {
        if(b&1)
            sum=sum*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return sum;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
    {
        int ans=0
        char ch = '?';
        int nnn = 0;
        cin>>n;
        cin>>s;
        s=" "+s;
        for(int i = 1; i <= n; i++)
        {
            if(s[i] == ch)
            {
                nnn ++;
                continue;
            }
            ch = s[i];
            ans = (ans + (quickpow(2, nnn) - 1)) % MOD;
            nnn = 1;
        }
        cout<<(ans + (quickpow(2, nnn) - 1)) % MOD<<"\n";
    }
    return 0;
}

 D. GCD Queries

题解:

这里有一个长度为 n 的 [0...n−1] 的排列 a 

你可以最多询问 2∗n 次,每次给出两个数字 x,y ,程序会给你gcd(a_{x},a_{y})的值。

最后请输出 x,y 使得 a_{x},a_{y}中有一个是0

当n=2时,x=1,y=2

当n>2时,还是令x=1,y=2,

枚举i,(3<=i<=n),每次询问(x,i)和(y,i)

gcd(a_{x},a_{i})= gcd(a_{y},a_{i}),则排除第i个数为0,

因为若第i个数为0,则gcd(a_{x},a_{i})=a_{x},gcd(a_{y},a_{i})=a_{y}

0\leq a_{x},a_{y}\leq n-1,a_{x}\neq a_{y},则若第i个数必不为0

gcd(a_{x},a_{i})\neq gcd(a_{y},a_{i}),不妨设ax=gcd(a_{x},a_{i}),ay=gcd(a_{y},a_{i})

且令ax<ay,此时a_{i}可能为0,而a_{x}必不为0,

a_{x}等于0,则ax=a_{i}ay=gcd(a_{y},a_{i})\leq a_{i},而ax<ay,则矛盾

a_{x}必不为0,此时ax=gcd(a_{x},a_{i}),ay=gcd(a_{y},a_{i})gcd(a_{x},a_{i})\neq gcd(a_{y},a_{i})

a_{i}可能为0,则用a_{i}来替换a_{x}

最后输出x和y即可

#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e6;
int n,m,x,y,z,t,k,q;
int ans,res;
string s;
signed main()
{
    int T=1;
    cin>>T;
    while(T--)
    {
        cin>>n;
        x=1,y=2;
        int ax,ay;
        if(n==2)
        {
            cout<<"! "<<1<<" "<<2<<endl;
            cin>>ans;
            continue;
        }
        for(int i=3;i<=n;i++)
        {
            cout<<"? "<<x<<" "<<i<<endl;
            cin>>ax;
            cout<<"? "<<y<<" "<<i<<endl;
            cin>>ay;
            if(ax==ay)continue;
            else
            {
                if(ax<ay)
                {
                    x=i;
                }
                else
                {
                    y=i;
                }
            }
        }
        cout<<"! "<<x<<" "<<y<<endl;
        cin>>ans;
    }
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值