cf769题解

Codeforces Round #769(div2)

ABCD的题解

大家好,因为小编水平限制,只会写出div2前四题的题解

A.ABC

A题链接
题意:给定长度为n的01串,可以对这个串重新任意排列,问是否存在一种排列,使得该串的任意一个长度大于1的子串都不为回文串。
思路:根据规律我们可以得到1、0、10、01均是NO,其他情况均是YES。
代码:

#include<bits/stdc++.h>
using namespace std;
void solve()
{
    int n;
    cin>>n;
    string s;
    cin>>s;
    if(n==1)
    {

        cout<<"YES"<<endl;
        return;
    }
    if(n==2)
    {
        if(s[0]!=s[1])
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
        return ;
    }
    cout<<"NO"<<endl;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}

B.Roof Construction

B题链接
题意:题意:给定一个n,表示有一个长度为n的数组p,元素是 0,1,2,…,n−10,1,2,…,n−1,要求对这个数组重新排列,使得pi xor pi+1的最大值最小,输出排列后的数组。
思路:我们设答案为k,则我们先让[0 k]先配对,然后把剩下的的数分两组,[1 k-1]和[k+1,n-1]
第一组的任意排列,其相邻的xor值都不会大于k,第二组也是,因为最高位1被消掉了。
那么就是边界问题了,主要是第二组,一定会有一个数字是和别的数字接触的,那么我们用k去接触,把它的最高位消掉即可。
那么就可以排列出 n−1,n−2,…,k,0,1,2,…,k−1
代码:

#include<bits/stdc++.h>
using namespace std;
void solve()
{
    int n;
    cin>>n;
    int k=1;
    while(k<n)
    {
        k<<=1;
    }
    k>>=1;
    for(int i=n-1;i>=k;i--)
    {
        cout<<i<<" ";
    }
    cout<<"0 ";
    for(int i=1;i<k;i++)
    {
        cout<<i<<" ";
    }
    cout<<endl;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}

C.Strange Test

C题链接
题意:给两个数a,b,有以下三种操作,每个操作都可以做任意次,问最少几次操作可以使a和b相等

1、a = a + 1

2、b = b + 1

3、a = a | b
思路: 首先容易看出,最后使得a和b相等的操作,要不就是第一种,要不就是第三种如果是第一种的话,答案就是b - a,如果是第三种的话,那么最后一步之前一定存在a | b = b。
因此我们一开始用b-a作为我们的初始值,之后我们用枚举对比,当到达k之后,k|a=b,此时让b-a与k-a+1进行比较即可,然后再特判一下i|a=i的i,此时i必须大于b,我们先让b加到i,再和a或得到i,这个地方i必须是大于b切满足i|a=i的最大整数,再和i-b+1比较。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
    int a,b;
    cin>>a>>b;
    int res=b-a;//第一种情况
    for (int i = a; i <= b; i ++ ) {
        if ((i | b) == b) {
         res = min(res, i - a + 1);//直接或得到
            break;
        }
    }
    for (int i = b; i>0; i ++ ) {
        if ((i | a) == i) {
  res = min(res, i - b + 1);//改变b值后或运算得到
            break;
        }
    }
    cout << res << endl;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}

D.New Year Concert

D题链接
题意:给定一个长度为n的数组a,我们定义一个数组是bad,当且仅当存在这么一对 [l,r][l,r] 使得 gcd(al,al+1,…,ar)=r−l+1gcd(al,al+1,…,ar)=r−l+1。
我们可以通过改变数组中的数来避免这一现象。
定义 f(a)f(a) 为对于长度为k的数组中,至少要改变多少的数使得不存在bad数组。
对于一个长度为n的数组a,求出 f(a1),f(a1,a2),…,f(a1,a2,…,an)
思路:对于一段连续的数来说,gcd是单调递减的,数组长度是单调递增的。所以最多只存在n个bad数组。所以我们对于每个左边界 ll,最多能找到一个 rr 满足bad数组的定义。以上方法可以通过二分查找出。那么查到以后,我们的想法是直接修改成一个大质数即可,由于原数组值域只有1e9,我们修改为1e9 + 7由此可知,我们需要用到单点修改,区间gcd查询,二分,用线段树即可实现
代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 200000, LN = 20;

int f[N][LN];
int n;
int a[N];

int gcd(int a, int b)// dddd
{
    if(b == 0) return a;
    else return gcd(b, a % b);    
}

void init() //st预处理所有区间的的gcd
{
    for(int st = 0; (1 << st) <= n; st ++)
        for(int i = 0; i <=  n - (1 << st); i ++)
        {
            if(st == 0)
            {
                f[i][st] = a[i];
                continue;
            }

            f[i][st] = gcd(f[i][st - 1], f[i + (1 << (st - 1))][st - 1]);
        }
}

int getgcd(int l, int r) //st的查询函数
{
    int st = __lg(r - l + 1); //找到最高位位数的__lg函数
    return gcd(f[l][st], f[r - (1 << st) + 1][st]);
}


int main()
{
    cin >> n;

    for(int i = 0; i < n; i ++) cin >> a[i];
    init();
    int maxr = -1;
    int be = 0;
    int res = 0;

    //区间贪心,找到最小的r并让所有包含r的区间(for a fixed l, as r increaes, gcd never changes;you should use less operates to make value as a
    // as great as possible, so by iterating ,you can obtain a r(max), which getgcd(l, r) >= r - l + 1)全部砍掉(a[r] == a big prime)
    for(int i = 0; i < n; i ++)
    {
        while(be < i && getgcd(be, i) < i - be + 1) be ++;
        if(getgcd(be, i) == i - be + 1)
            if(be > maxr)
            {
                res ++;
                maxr = i;
            }

        cout << res << ' ';
    }

    return 0;
}

上一篇:AcWing 796. 子矩阵的和


下一篇:ADB keyevent 汇总