Codeforces Round #595题解报告

A、Yet Another Dividing into Teams

题意是n个学生,每个学生的能力值不同,现在要求将这些分组,且能力值相差为一的学生不能同一组。
思路,其实考虑一下的话最多分成两组,如果任意两个能力值相差大于1,那么一定可以分为一组,但凡有一对相差为1,那么一定分为两组。
排序,再遍历查询。
算是水题吧。

B1、Books Exchange(easy version)

题意是给你一个序列,第 i 个数可以到达第a[i]位置,问最少几次能够回到 i 。
大体思路,因为是简单问题,数据比较少,直接模拟路径,然后计数即可。
感觉时间复杂度会很高……

B2、Books Exchange(hard version)

这道题其实就是B1题扩大了数据范围。
其实考虑一点,序列中每个数都在一个简单的环中,在这个环中,每个点的答案都是一样的。然后再用一个数组记录每个点的次数即可。
参考了好多博客,也有说用并查集的,但这道题其实就是一个记忆化模拟路径。

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int a[N],ans[N];
int main()
{
    
    
    int t;
    cin >> t;
    while(t--)
    {
    
    
        memset(ans,0,sizeof(ans));
        int n;
        cin >> n;
        for(int i=1; i<=n; i++)
            cin >> a[i];
        for(int i=1; i<=n; i++)
        {
    
    
            if(ans[i]) continue;
            int t=a[i],cnt=1;
            queue<int> q;
            q.push(i);
            while(t!=i)
            {
    
    
                cnt++;
                q.push(t);
                t = a[t];
            }
            while(q.size())
            {
    
    
                t=q.front();
                q.pop();
                ans[t]=cnt;
            }
        }
        for(int i=1; i<=n; i++)
            cout << ans[i] << " ";
        cout <<endl;
    }
    return 0;
}

C1、Good Numbers (easy version)

题意大体是,定义“good number”是只由一些 3 i 3^i 3i的数相加,且 i 不能相同的数。给定一个整数n,找到不比n小的最小“good number”。
思路,首先看该题是简单问题,所有数据较小,可以直接一点。因为大于等于n的good number必然是由一些 3 i 3^i 3i的数相加,那么,可以考虑的是n%3的结果,如果n%3余数是2,那么必然有两个或者更多的相同 3 i 3^i 3i,那么n不可能是好数,n++;如果余数是1或者0,那么n/=3继续往下判断即可。
代码确实不怎么好写,想了想这个题目其实应该涉及到三进制的问题,但又不知道怎么去考虑,直接暴力解决的。

C2、Good Numbers (hard version)

题意同上C1,但数据范围变大了,所以暴力肯定超时。
考虑一下这道题目的本质问题,既然“good number”是只由一些 3 i 3^i 3i的数相加,且 i 不能相同的数,那么这个好数就可以写成一个三进制的形式,然后对这个三进制进行操作。
如果三进制某一位是2的话,那么要把这一位清零然后上一位加一,当然,这样其实不是最小的解,想要最小的解的话,记录最后一次改变的位置,记录,然后将其后面的位数全部至于零,然后再把这个三进制数转化成10进制输出即可。
确实学到了进制转换一招。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
int a[N];
int main()
{
    
    
    ll n,t;
    cin>>t;
    while(t--)
    {
    
    
        memset(a,0,sizeof a);
        cin>>n;
        int len=0;
        while(n)//将n转化为三进制
        {
    
    
            a[len++]=n%3;
            n/=3;
        }
        int pos=-1;
        for(int i=0; i<len; i++)
        {
    
    
            if(a[i]>=2)
            {
    
    
                pos=i;a[i]=0;a[i+1]++;
                if(i+1==len)
                    len++;
            }
        }
        if(pos!=-1)
            for(int i=0; i<=pos; i++)
                a[i]=0;
        ll sum=0,temp=1;
        for(int i=0; i<len; i++)
        {
    
    
            sum+=a[i]*temp;
            temp*=3;
        }
        cout << sum <<endl;
    }
    return 0;
}

D1、D2、Too Many Segments

题意大体是,有n条线段,对于每个点其覆盖次数不能超过k,问至少移除几条线段才能满足要求。
还没开始整理。

猜你喜欢

转载自blog.csdn.net/qq_45949914/article/details/107292819
今日推荐