Codeforces Round #721 (Div. 2)

2021.5.20

A

题意:给一个整数n,求出最大的k,其中n&(n-1)&...&k=0

题解:只需要让n每次递减的数每个二进制位都有存在0,可想k就是n的最高位为1其他位都为0的数m-1,这样可以保证每位二进制位都有0

#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
int main()
{
    ios_base::sync_with_stdio(false);
    ll t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        if(n==1)
            cout<<0<<endl;
        else if(n==2)
            cout<<1<<endl;
        else{
              ll k=1;
        while(k<n){
            k*=2;
        }
        if(k!=n)
        k/=2;
        cout<<k-1<<endl;
        }
    }
    return 0;
}

B1

题意:规则:每次只能有两个操作:1、把0变成1花费1 ;2、若现在字符串的状态不为回文串,那可以把子符串颠倒,若为回文串或者上一回合用了翻转,则只能用操作1,不能翻转。给一个回文字符串,只包含0和1,ALICE先手,BOB后手,最后把字符串都变为1谁花费的多,一样的话输出“DRAW”。

题解:只需判断子串串0的个数,若无0肯定就是平局,如果0的个数为奇数,那么证明字符串长度为奇数,且最中间的为0,这种情况如果只有1个0那么肯定是先手输,如果大于1,则后手必输(比如“10001”,先手拿掉中间的,字符串又是回文,后手只能拿花费1,然后先手翻转,后手又只能花1),如果0的个数为偶数,那么先手必输。(最后剩两个先手每次必花费1,后手翻转,最后一个又只能先手花费1)

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    int t,n;
    string s;
    cin>>t;
    while(t--)
    {
        cin>>n>>s;
        int k0=0,k1=0,len=s.size();
        for(int i=0;i<n;i++)
        {
            if(s[i]=='0')
                k0++;
            else
                k1++;
        }
        if(k0==0)
            cout<<"DRAW"<<endl;
        else
        {
            if(k0%2)
            {
                if(k0==1)
                    cout<<"BOB"<<endl;
                else
                    cout<<"ALICE"<<endl;
            }
            else
            {
                cout<<"BOB"<<endl;

            }
        }
    }
    return 0;
}

B2

题意:再B1的基础上,输入的子符串不一定是回文串。

题解:只需枚举出不是先手赢的情况:0个数为2且只有一个不对称的位置,一样是平局,如果是回文串且0的个数是偶数或者0的个数为1,那么就是后手赢,其他情况都是先手赢(先手有拿或者翻转的选择,所以可以去掉自己输的情况,把自己输的情况给后者)

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <string>
using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    int t,n;
    string s;
    cin>>t;
    while(t--)
    {
        cin>>n>>s;
        int dif=0;
        for(int i=0;i<(n+1)/2;i++)
        {
            if(s[i]!=s[n-i-1])
                dif++;
        }
        int num=count(s.begin(),s.end(),'0');
        if(!dif&&(num%2==0||num==1))
            cout<<"BOB"<<endl;
        else if(dif==1&&num==2)
            cout<<"DRAW"<<endl;
        else
            cout<<"ALICE"<<endl;
    }
    return 0;
}

C

题意:给一个长度为n的整数序列a,其中若整数对 i<j && ai=aj 则这一整数对贡献为1,其中不同子序列若有重复的位置贡献属于不同的贡献,计算序列a的所有子序列的贡献和。

题解:dp[i]的贡献=dp[i-1]的贡献+包含ai这个数的子序列的贡献(前面所有等于ai的数的下标和*后面包含ai还要几个数可以作为子序列)

#include <iostream>
#include <algorithm>
#include <map>
#define ll long long
using namespace std;
int main()
{
    ios_base::sync_with_stdio(false);
    int t,n,x;
    cin>>t;
    while(t--)
    {
        cin>>n;
        map<int,ll>m;
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            sum+=m[x]*(n-i+1);
            cout<<m[x]*(n-i+1)<<endl;
            m[x]+=i;
        }
        cout<<sum<<endl;
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值