Codeforces Round #751 (Div. 2)部分题解(A ~ C)

前言

沾了3位姐姐的光,红包抢到了不少,嘻嘻。

在这里插入图片描述
虽然说打铁了,但是前四发都是一发入魂,比起博主CF的A题都要WA上一发,这也太猛了。
果然,博主身边全都是猛人,只有博主是个fw。

在这里插入图片描述

最后缅怀一下被送走的李哥,怕不是半夜睡觉的时候被窝里全是凯南。


A - Two Subsequences (水题)

比赛链接:https://codeforces.com/problemset/problem/1602/A

题目大意

现在给出字符串 s s s,你的任务是把它拆分成两个字符串 a a a b b b

字符串 a a a b b b满足:

  1. 字符串 a a a与字符串 b b b都是字符串 s s s的子序列;
  2. 字符串 s s s的所有字符 s i s_i si必须出现在字符串 a a a或字符串 b b b之中;
  3. 字符串 a a a的字典序要尽可能地小,字符串 b b b无所谓;

请输出符合条件的字符串 a a a b b b

思路

样例给了我灵感:字符串 a a a只是被限制了字典序,并没有被限制长度。
在这里插入图片描述
所以我们直接把字符串 s s s字典序最小的字符单拿出来作为字符串 a a a,剩下的就是字符串 b b b

太水了。

AC代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
    
    
    int t;
    cin>>t;
    while(t--){
    
    
        string ss;
        cin>>ss;
        int pos=0;
        for(int i=1;i<ss.size();i++){
    
    
            if(ss[i]<ss[pos])pos=i;
        }
        cout<<ss[pos]<<" ";
        for(int i=0;i<ss.size();i++){
    
    
            if(i==pos) continue;
            cout<<ss[i];
        }
        cout<<endl;
    }
}

B - Divine Array(思维+离线处理)

比赛链接:https://codeforces.com/problemset/problem/1602/B

题目大意

现在给出一个长度 n n n( n < = 2000 n<=2000 n<=2000)的数组 a a a
接下来我们持续对数组 a a a做同一种操作:让 a i a_i ai变成 a i a_i ai在数组中出现的次数。

例如,数组a初始为:2 1 1 4 3 1 2
在第一次操作之后,数组a会变为:2 3 3 1 1 3 2
在第二次操作之后,数组a会变为:2 3 3 2 2 3 2
在第三次操作之后,数组a会变为:4 3 3 4 4 3 4
在第四次操作之后,数组a会变为:4 3 3 4 4 3 4

现在有 q q q次询问,每次询问有两个数字 x x x k k k,请你输出 a x a_x ax k k k次变换之后会变成多少。

思路

了解过莫队算法的同学应该都知道离线处理的概念。
简单来说,离线处理就是将所有的询问全部先存储起来,然后一起处理掉。

对于一些题目(例如本题),题目中会给出数次询问,需要你输出每次询问的答案。
正常的做法就是问一次答一次:

第一次询问:1~4的和?
第一次回答:1~4的和为10
第二次询问:1~6的和?
第二次回答:1~6的和为21
...

但实际上,我们可以先把问题全部存储一起,然后一起回答:

询问时间:
第一次询问:1~4的和?
第二次询问:1~6的和?
...

回答时间:
第一次询问的答案:10
第二次询问的答案:21
...

能否使用离线处理的关键在于问题之间是否存在联系

我们以本题的第一个样例举例:
在这里插入图片描述
假设我们是一个暴力的写法,对于每一次询问,我们都从第 0 0 0次开始暴力模拟一遍到第k次,这就浪费了大量的时间,增加了 T T T掉的风险。

而在这四次询问中我们注意到,在我们处理掉第二次询问之后,此时我们已经对数组a进行了1次操作。
这个时候我们其实是可以跳过第三次询问,先去回答第四次询问的。
所以此时我们可以使用离线处理的办法,把所有的询问全部读入之后进行排序(按照k的值由小到大)。这样的话整个寻找答案的过程中,我们其实是只是一个 O ( n ) O(n) O(n)的过程。

再观察题目中举出的例子,我们可以发现:一个数组在操作数次之后会达到一个终态(例如例子中的4 3 3 4 4 3 4)。
所以我们在变化的时候再加以判断此次变化之后数组 a a a与变化之后的数组 a ′ a' a是否完全一致。如果一致的话说明此时数组 a a a达到了饱和的终态,接下来再变几次都是这个数组了。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;

struct node
{
    
    
    int x,k,p;   //第p个问题:x k
} arr[maxn];

bool cmp1(node a,node b)
{
    
    
    return a.k<b.k;
}

int ans[maxn];
int a[2050];

int main()
{
    
    
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
    
    
        map<int,int> mp;
        int n,q,x;
        cin>>n;

        for(int i=1; i<=n; i++)
            cin>>a[i];

        cin>>q;
        for(int i=1; i<=q; i++)
        {
    
    
            cin>>arr[i].x>>arr[i].k;
            arr[i].p=i;
        }

        sort(arr+1,arr+q+1,cmp1);

        int cnt=0,pos=1;
        int flag=0;    //数组a是否达到终态
        while(pos<=q)
        {
    
    
            if(arr[pos].k==cnt||flag)
                ans[arr[pos].p]=a[arr[pos].x];
            else
            {
    
    
                while(cnt!=arr[pos].k)
                {
    
    
                    mp.clear();
                    for(int i=1; i<=n; i++)
                        mp[a[i]]++;
                    int ff=1;
                    for(int i=1; i<=n; i++)
                    {
    
    
                        if(a[i]!=mp[a[i]]) ff=0;
                        a[i]=mp[a[i]];
                    }

                    if(ff)
                    {
    
    
                        flag=1;
                        break;
                    }
                    cnt++;
                }
                ans[arr[pos].p]=a[arr[pos].x];
            }
            pos++;
        }
        for(int i=1; i<=q; i++)
            cout<<ans[i]<<endl;
    }
}

C. Array Elimination(位运算+GCD)

比赛链接:https://codeforces.com/problemset/problem/1602/C

题目大意

现给出长度为n的数组 a a a
你每次可以选择数组 a a a的一个长度为 k k k的子序列 a ′ a' a,求出这个子序列 a ′ a' a位与和,然后让 a ′ a' a中的每个元素都减去这个位与和
你可以操作无数次,最后把数组 a a a中的所有数字都变成 0 0 0

请求出 k k k的所有值。

思路

首先先来了解一下位运算中的与运算:双1得1,其他为0。

1&1=1
1&0=0
0&1=0
0&0=0

我们把数组 a a a中的所有数都化为 2 2 2进制,并统计每一位上 1 1 1出现的个数,得到二维数组 n u m num num

  a :2 5 3
a[1]:0 1 0
a[2]:1 0 1
a[3]:0 1 1
 num:1 2 2

那么我们每次的操作实际上就是让 n u m i − k num_i-k numik,直到把 n u m num num中所有的数都变成 0 0 0为止。
k k k的最大值也就出现了: G C D ( n u m 1 , n u m 2 , n u m 3 . . . . n u m n ) GCD(num_1,num_2,num_3....num_n) GCD(num1,num2,num3....numn)
既然如此, k k k的所有因子显然也是满足条件的。

不过需要特判一点:如果所有的数相等,那么 k k k的值就可以是 1 1 1~ n n n中任意一个数。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;

int num[40];

int main()
{
    
    
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n,x;
        cin>>n;
        memset(num,0,sizeof(num));
        for(int i=0; i<n; i++)
        {
    
    
            cin>>x;
            int cnt=0;
            while(x)
            {
    
    
                if(x&1)
                    num[cnt]++;
                cnt++;
                x>>=1;
            }
        }
        vector<int> arr;
        for(int i=0; i<=30; i++)
            if(num[i])
                arr.push_back(num[i]);
        if(arr.size()==0)
        {
    
    
            for(int i=1;i<=n;i++)
            {
    
    
                if(i!=1) cout<<" ";
                cout<<i;
            }
            cout<<endl;
        }
        else
        {
    
    
            int ans=arr[0];
            for(int i=1; i<arr.size(); i++)
                ans=__gcd(ans,arr[i]);
            int tmp=0;
            for(int i=1; i<=ans; i++)
            {
    
    
                if(ans%i==0)
                {
    
    
                    if(tmp)
                        cout<<" ";
                    cout<<i;
                    tmp++;
                }
            }
            cout<<endl;
        }
    }
}

后话

感谢阅读,希望能对你产生一点用处。
以下台词取自《银魂》第62集(红樱篇处37小天使对银时的评价):

在这里插入图片描述

"副长,那个老板似乎不是凭我能揣度明白的人。"
"有种抓不着要领的感觉,搞不清他到底是被爱戴还是被憎恨。"
"明明会给身边的人带来麻烦,但人们却会向他聚集。"
"啊?你问的不是这些?"
"攘夷志士?这个,我也不太清楚。"
"但是,攘夷活动之类的,那个人肯定没想过这些烦琐的事吧。"
"我觉得那个人他一定只是,想看到那女孩的笑容吧。"

吾日三省吾身:日更否?刷题否?快乐否?
更新了,但不是日更;已刷;平静
路漫漫其修远兮,吾将上下而求索

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45750296/article/details/121055369