Codeforces Round #601 (Div. 2)题解 by_Hile

前言:前几天晚上打了一场Div1+2后终于上蓝,为了纪念,这周就写这一场的题解了。

题目链接


A.Changing Volume

水题,贪心。优先移动5格,然后2格,最后1格。

#include<bits/stdc++.h>
using namespace std;
int T,x,y;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>x>>y;
        if(y<x)swap(x,y);
        if(x==y)cout<<0<<"\n";
        else
        {
            int tt=(y-x)/5;
            cout<<(tt+(y-x-tt*5)/2+(y-x-tt*5)%2)<<"\n";
        }
    }
}

B.Fridge Lockers

水题。当点数不小于边数时,若要使每个点至少连两个边,只能形成一个大环。

#include<bits/stdc++.h>
using namespace std;
int T,n,m,a;
int main()
{
    cin>>T;
    while(T--)
    {
        int sum=0;
        cin>>n>>m;
        for(int i=1;i<=n;i++)cin>>a,sum+=a;
        if(n==2||m<n)
        {
            cout<<-1<<"\n";
            continue;
        }
        else cout<<sum*2<<"\n";
        for(int i=0;i<n;i++)
            cout<<(i)%n+1<<" "<<(i+1)%n+1<<"\n";
    }
}


C.League of Leesins

观察发现当 n 5 n\geq 5 时, 1 1 n n 只存在于一个三元组, 2 2 n 1 n-1 只存在于两个三元组,其他元素都存在于三个三元组。所以可以记录每个数字的出现次数和所属的三元组,然后从出现次数为 1 1 的数字所载的三元组开始删除(出现次数–),然后寻找下一个出现 1 1 次的数,删除顺序就是答案。时间复杂度 O ( n ) O(n)

注意删到最后会出现一个次数为 1 , 1 , 1 1,1,1 的三元组,此时应根据其最初出现次数由大到小放进答案,否则亲身试验会WA2(

#include<bits/stdc++.h>
#define N 100010
using namespace std;
int T,n,m,a[N],vis[N],pre[N],v[N];
int t[N][3];
vector<int> G[N],ans;
bool cmp(int a,int b)
{
    return pre[a]>pre[b];
}
void dfs(int x)
{
    if(vis[x]==1)
    {
        ans.push_back(x);
        for(int j=0;j<G[x].size();j++)
        {
            if(v[G[x][j]])continue;
            int* tmp=t[G[x][j]];
            v[G[x][j]]=1;
            if(vis[tmp[0]]==1&&vis[tmp[1]]==1&&vis[tmp[2]]==1)
            {
                ans.pop_back();
                sort(tmp,tmp+3,cmp);
                for(int k=0;k<3;k++)
                    ans.push_back(tmp[k]);
                for(int k=0;k<n;k++)cout<<ans[k]<<" ";
                exit(0);
            }
            for(int i=0;i<3;i++)vis[tmp[i]]--;
            for(int i=0;i<3;i++)dfs(tmp[i]);
        }
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n-2;i++)
        for(int j=0;j<3;j++)
        {
            cin>>t[i][j];
            vis[t[i][j]]++;
            pre[t[i][j]]++;
            G[t[i][j]].push_back(i);
        }
    for(int i=1;i<=n;i++)
        dfs(i);
}

D.Feeding Chicken

首先算出 l i m = c n t R K lim=\lfloor\frac{cnt_R}{K}\rfloor 即为每种颜色最低分配的 R R 的数量,我们可以从上到下 S S 型贪心涂色。对于前 ( c n t R K l i m ) × ( l i m + 1 ) (cnt_R-K*lim)\times(lim+1) R R 来说,每 l i m + 1 lim+1 R R 的颜色都是相同的;在这之后,每 l i m lim R R 涂一种颜色即可。时间复杂度 O ( n m ) O(nm)

#include<bits/stdc++.h>
using namespace std;
int T,n,m,k;
char a[111][111];
vector<char> c;
int main()
{
    for(char i='a';i<='z';i++)c.push_back(i),c.push_back(i-'a'+'A');
    for(char i='0';i<='9';i++)c.push_back(i);
    scanf("%d",&T);
    while(T--)
    {
        int cnt=1,num=0;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",a[i]+1);
            for(int j=1;j<=m;j++)cnt+=(a[i][j]=='R');
        }
        for(int i=1;i<=n;i++)
            if(i&1)
                for(int j=1;j<=m;j++)
                {
                    if(a[i][j]=='R')num++;
                    a[i][j]=c[num*k/cnt];
                }
            else
                for(int j=m;j>=1;j--)
                {
                    if(a[i][j]=='R')num++;
                    a[i][j]=c[num*k/cnt];
                }
        for(int i=1;i<=n;i++)
            printf("%s\n",a[i]+1);
    }
}

E1&2.Send Boxes to Alice

S i S_i 表示所给数列前 i i 项之和,若使所有盒子里的数都能被大于 1 1 的数 k k 整除,则 k k 必是 S n S_n 的质因子。因此,我们可以预处理出所有可能的素因子 k k

对于每一个 k k ,设 i i 位置之前都满足 k S n k|S_n S n S_n 能被 k k 整除),则对于第 i i 个位置来说,若要满足题目条件,只能将第 i i 个位置的数减少(从 i i 向后分)或增加(从 i i 之后向 i i 分),对答案的贡献即为 m i n ( S i % k , k S i % k ) min(S_i\%k,k-S_i\%k) 。枚举所有可能的 k k 并线性时间内处理答案取最小值即可。时间复杂度 O ( δ n ) O(\delta n) δ \delta S n S_n 的素因子个数,为 1 0 2 10^2 之内的常数。

#include <bits/stdc++.h>
#define ll long long
#define N 1000010
using namespace std;
int n;
ll a[N],sum[N],tmp,ans=(1LL<<60);
vector<ll> fac;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i];
    tmp=sum[n];
    if(tmp==1)
    {
        cout<<-1;
        return 0;
    }
    for(ll i=2;i*i<=tmp;i++)
        if(tmp%i==0)
        {
            while(tmp%i==0)tmp/=i;
            fac.push_back(i);
        }
    if(tmp>1)fac.push_back(tmp);
    for(auto it:fac)
    {
        ll s=0;
        for(int i=1;i<n;i++)
            s+=min(sum[i]%it,it-sum[i]%it);
        ans=min(ans,s);
    }
    cout<<ans;
}

F.Point Ordering

未完待续


发布了7 篇原创文章 · 获赞 10 · 访问量 438

猜你喜欢

转载自blog.csdn.net/weixin_44700995/article/details/103178191