Codeforces Round #796 (Div. 2)A-C题解

本文介绍了如何使用位运算解决Codeforces编程竞赛中的三个问题。第一题涉及找到满足特定位运算条件的最小正整数;第二题讨论了通过融合和减法操作使所有令牌的魔力值为奇数的最少步骤;第三题通过分析字符串操作的奇偶性来恢复原始历史。解题思路包括分析奇偶性、位运算技巧和字符串操作的规律。
摘要由CSDN通过智能技术生成

@[TOC](Codeforces Round #796 (Div. 2))

A.Cirno’s Perfect Bitmasks Classroom

在这里插入图片描述
在这里插入图片描述
题目大意:奇诺给他的学生一个正整数x,并且布置了一项作业,要求她的学生找到最小的正整数满足这两个条件:x&y>0并且x xor y > 0;
思路:有位运算,肯定要跟二进制数联系起来,首先,我们需要知道,一个偶数的二进制数的最左边一定是0,而奇数的二进制数的最左边一定是1。分奇偶考虑,若为奇数,要想满足上面两个式子,若x != 1,则y = 1,若x=1,则y = 3;若为偶数,需要找到该数从左往右第一个为1的位置,然后,在x为偶数时,若第一个出现1的位置不是最后一个出现1的位置,那么直接把该位往左的数全部看成0,输出即可,若只有一个1时,输出x+1即可(不理解的可以举几个例子试试)。

/*
 author : Mzx
*/
#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn = 1e5+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define x first
#define y second
 
 
int read () {
    int k=0,f=1;
    char c=getchar ();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar ();}
    while (c>='0'&&c<='9') {k=k*10+c-'0';c=getchar ();}
    return k*f;
}
 
void solve() {
    int n; cin >> n;
    if(n & 1)
    {
        if(n == 1)
        {
            cout<<"3"<<endl;
        }
        else
        {
            cout<<"1"<<endl;
        }
    }
    else
    {
        int m = 0;
        int p = n;
        while((p&1) == 0) {
            p = p >> 1;
            m++;
        }
        int ans = 2 << (m-1);
        if(ans == n)
            cout << ans + 1<< endl;
        else
            cout<<ans<<endl;
    }
}
 
int main()
{
    ios;
    int t;cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}

B. Patchouli’s Magical Talisman

在这里插入图片描述
在这里插入图片描述
题目大意:广藿香正在制作一个神奇的护身符。她最初有n魔法令牌。他们的神奇力量可以用正整数a1,a2, … ,an来表示。

广藿香可以对令牌执行以下两种操作。

融合:广藿香选择两个标记,移除它们,并创造一个新的标记,其魔力等于两个所选标记之和。
减法:广藿香选择魔力值相等的令牌X,将其移除并创建一个新的令牌,其魔力等于X/2.
当它们的魔力是奇数时,令牌会更有效。请帮助广藿香找出她需要的最少操作次数,以使所有代币的魔力为奇数。

思路:首先先算出a数组中偶数和奇数的个数分别为多少,如果全为奇数,答案为0,如果全为偶数,那么为了找出最少操作次数,先把一个最小的偶数通过“减法操作”变成1,再进行n-1次融合操作。(偶数和偶数相加还是偶数,偶数和奇数相加是奇数)如果有奇数有偶数,则直接输出偶数个数即可。(偶数与奇数相加

/*
 author : Mzx
*/
#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
typedef long double ld;
typedef pair<int,int> PII;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn = 2e5+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define x first
#define y second
 
 
int read () {
    int k=0,f=1;
    char c=getchar ();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar ();}
    while (c>='0'&&c<='9') {k=k*10+c-'0';c=getchar ();}
    return k*f;
}
 
void solve()
{
    int n; cin>>n;
    int num_even = 0; //偶数的数量
    int ans = INF;
    for(int i = 1;i <= n;i ++)
    {
        int x;cin>>x;
        if(x%2==0) num_even++;
        int pos = 0; //记录一个偶数递归/2,到1需要的步数
        while(x%2==0)
        {
            pos++;
            x/=2;
        }
        ans = min(ans,pos);
    }
    if(num_even != n) cout << num_even << endl;
    else cout << ans + num_even - 1 << endl;
}
 
 
int main()
{
    ios;
    int t; cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

C. Manipulating History

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目大意:
凯因有能力操纵历史。

幻想乡的历史最初是一个长度为1的字符串s。要修复由香里造成的混乱,她需要做以下操作n次,对于每一次操作:

1.她选择了一个s的非空子字符串 t2i-1.
2.她用一个非空的字符串 t2i来替换t2i-1.注意,这两个字符串的长度可以不同。
请注意,如果t2i-1不止一次出现在s,则其中一个将被替换。

例如,让s=“marisa”,t2i-1=“a”,和t2i=“ z ”,操作后,s变成“ mzrisa ”或“ marisz ”。

在n次操作后,Keine 得到了最终的字符串和一个操作序列t长度为2n. 就在凯涅认为她已经完成的时候,由香里再次出现并洗牌了。更糟糕的是,Keine 忘记了最初的历史。

帮助 Keine 找到幻想乡的最初历史!

回想一下,子字符串是字符串的一系列连续字符。例如,对于字符串“ abc ”,它的子字符串是:“ ab ”、“ c ”、“ bc ”等。但以下字符串不是它的子字符串:“ ac ”、“ cba ”、“ acb ”

思路:该题是一个结论题,在操作过程中,出现次数为奇数的字符即为最初的字符。因为最初的字符只在第一次进行操作时被输入,其他的字符串均在被操作时和操作后得到的字符串中出现,故两两一对出现,所以出现次数必为偶数。

/*
 author : Mzx
*/
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int,int> PII;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn = 2e5+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define x first
#define y second


int read () {
    int k=0,f=1;
    char c=getchar ();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar ();}
    while (c>='0'&&c<='9') {k=k*10+c-'0';c=getchar ();}
    return k*f;
}

int ch[maxn];

void solve()
{
    memset(ch,0,sizeof ch);
    int n; cin >> n;
    n = 2 * n + 1;
    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        for(auto c : s) ch[c - 'a']++;
    }
//    cout<<ch[0]<<endl;
//    cout<<ch[25]<<endl;
    for(int i = 0;i < 26;i ++)
    {
        if(ch[i] & 1)
        {
            printf("%c\n",'a'+i);
            break;
        }
    }
}


int main()
{
    ios;
    int t; cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

膜拜 Yakumo_Ran(紫名大佬), SSerxhs(红名大佬)的位运算解法。Orz!

#include "bits/stdC++.h"
using namespace std;
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);
	int T;cin>>T;
	while (T--)
	{
		int n;
		char c=0;
		cin>>n;
		n=n*2+1;
		while (n--)
		{
			string s;
			cin>>s;
			for (auto x:s) c^=x;
		}
		cout<<c<<'\n';
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值