Codeforces Round #629 (Div. 3)题解

A.Divisibility Problem

给你两个数a,b,你可以使a增大或不变,问增大多少(或不变,即为0)能使a整除b

如果a=b,特判直接输出0即可。如果a不等于b,答案就是b-(a-(a/b)*b)。

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll inf=0x7f7f7f7f;
template<typename T>void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,a,b,ans;
bool flag;
int main()
{
    read(T);
    while(T--)
    {
        read(a);
        read(b);
        if(a%b==0)
        {
            write(0);
        }
        else
        {
            ans=b-(a-(a/b)*b);
            write(ans);
        }
        putchar('\n');
    }
    return 0;
}

B.K-th Beautiful String

给你字符串长度n和k,你可以使用两个字符b和无限个字符a(不超过字符串长度),问按照字典序排下去,第k个字符串是什么

我们经过观察可以知道有规律,1+2+3+4+。。。+n,这个公式的第k项等都和这两个b字符的坐标有关。设x,y是那两个b字符的字符串坐标,可以经过下面的一系列处理得到解。

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll inf=0x7f7f7f7f;
template<typename T>void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,n,k,x,y;
bool flag;
int main()
{
    read(T);
    while(T--)
    {
        read(n);
        read(k);
        x=y=0;
        while(x<k)
        {
            y++;
            x=y*(y+1)/2;
        }
        x=y*(y-1)/2;
        x=k-x;
        //cout<<x<<' '<<y<<endl;
        y=n-y;
        x=n+1-x;
        //cout<<x<<' '<<y<<endl;
        for(int i=1;i<=n;i++)
        {
            if(i==x||i==y)
            {
                putchar('b');
            }
            else
            {
                putchar('a');
            }
        }
        putchar('\n');
    }
    return 0;
}

C.Ternary XOR

给你一个数x,求a,b,能使(a+b)%3=x,且在满足条件的所有a,b中,max(a,b)最小

尽量的平分成两个大小相近的数,我们可以按照这样的处理方式进行。从最高位向最低位处理,如果原来这一位是0,则a,b这位都是0;在遇到第一个1之前,将2平分成1,1分到a和b;如果已经遇到1了,将他分给a,以后再遇到2和1,一律放到b。

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll inf=0x7f7f7f7f;
template<typename T>void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,n;
char ch;
int a[maxn],b[maxn],c[maxn];
bool flag;
void print(int *x)
{
    for(int i=0;i<n;i++)
    {
        write(x[i]);
    }
    putchar('\n');
}
int main()
{
    read(T);
    while(T--)
    {
        mem(a);
        mem(b);
        mem(c);
        flag=true;
        read(n);
        for(int i=0;i<n;i++)
        {
            ch=getchar();
            a[i]=ch-'0';
            if(a[i]==0)
            {
                b[i]=c[i]=0;
            }
            if(a[i]==1)
            {
                if(flag)
                {
                    b[i]=1;
                    c[i]=0;
                    flag=false;
                }
                else
                {
                    b[i]=0;
                    c[i]=1;
                }
            }
            if(a[i]==2)
            {
                if(flag)
                {
                    b[i]=1;
                    c[i]=1;
                }
                else
                {
                    b[i]=0;
                    c[i]=2;
                }
            }
        }
        print(b);
        print(c);
    }
    return 0;
}

D.Carousel

给你一个t数组,让你给他染色,如果t[i]!=t[i-1],则t[i]和t[i-1]不能染同一种颜色,若t[i]=t[i-1],你可以染成一种颜色,也可以染成不同颜色的。求染色用的颜色最少是多少及每个元素的颜色是什么(special judge,输出任意满足条件的解即可)。

如果t数组都相同,显然一种颜色足够
如果t数组是偶数个或第一个和最后一个是相同的,直接121212这样下去不会有冲突
如果t数组是奇数,
且相邻两个都不相同,则要三种,最后一个用3即可,可满足需求
且相邻两个有相同的,这个时候令他们其中一对是一种颜色,奇的剩下的当偶的处理

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const ll maxn=2e5+10;
const ll mod=1e9+7;
const ll inf=0x7f7f7f7f;
template<typename T>void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,n;
ll t[maxn];
bool flag;
int main()
{
    read(T);
    while(T--)
    {
        flag=true;
        read(n);
        read(t[0]);
        for(int i=1;i<n;i++)
        {
            read(t[i]);
            if(t[i]!=t[i-1])
            {
                flag=false;
            }
        }
        if(flag)
        {
            printf("1\n");
            for(int i=0;i<n;i++)
            {
                printf("1 ");
            }
            putchar('\n');
            continue;
        }
        if(n%2==0||t[0]==t[n-1])
        {
            write(2);
            putchar('\n');
            for(int i=0;i<n;i++)
            {
                if(i%2==0)
                {
                    write(1);
                }
                else
                {
                    write(2);
                }
                putchar(' ');
            }
            putchar('\n');
        }
        else
        {
            flag=false;
            for(int i=0;i<n;i++)
            {
                if(t[i]==t[i-1])
                {
                    flag=true;
                }
            }
            if(flag)
            {
                printf("2\n");
                for(int i=0;i<n;i++)
                {
                    if(t[i]==t[i-1])
                    {
                        flag=false;
                        printf("%d ",(i-1)%2+1);
                        continue;
                    }
                    if(flag)
                    {
                        if(i%2==0)
                        {
                            printf("1 ");
                        }
                        else
                        {
                            printf("2 ");
                        }
                    }
                    else
                    {
                        if(i%2==1)
                        {
                            printf("1 ");
                        }
                        else
                        {
                            printf("2 ");
                        }
                    }
                }
                printf("\n");
            }
            else
            {
                printf("3\n");
                for(int i=0;i<n;i++)
                {
                    if(i==n-1)
                    {
                        printf("3");
                    }
                    else if(i%2==0)
                    {
                        printf("1 ");
                    }
                    else
                    {
                        printf("2 ");
                    }
                }
                printf("\n");
            }
        }        
    }
    return 0;
}

E.Tree Queries

给你一棵树,和m个查询,每个查询描述了一个点集合(第一位是点集合个数),问这个点集合的在不在一条从根节点1开始到某一点的路径上(或离这条路距离为1)。

只会写A-D,E和F是后面看大佬代码改的,好像还有lca解法。离那条路径距离为1也满足条件,实际上就是他的父亲也在路径上。接下来的难点就是如何知道他们的父亲是不是在一条路径上,用dfs记录时间戳,知道如果在一条路径上,那么dfs过程中这些点的max(in[x])和min(out[x])应该是一样的。即v在不在1到u路径上,可以等价于u是不是v的子树,用dfs序可以实现。

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const ll maxn=2e5+10;
const ll mod=1e9+7;
const ll inf=0x7f7f7f7f;
template<typename T>void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
vector<int> edges[maxn];
ll in[maxn],out[maxn],fa[maxn];
ll T,n,m,cnt=0,tt,k,x,l,r,y;
bool flag;
void dfs(int v,int u)
{
    fa[v]=u;
    in[v]=++cnt;
    for(int i=0;i<edges[v].size();i++)
    {
        tt=edges[v][i];
        if(tt!=u)
        {
            dfs(tt,v);
        }
    }
    out[v]=cnt;
}
int main()
{
    mem(in);
    mem(out);
    mem(fa);
    read(n);
    read(m);
    for(int i=0;i<n;i++)
    {
        edges[i].clear();
    }
    for(int i=1;i<n;i++)
    {
        read(x);
        read(y);
        edges[x].push_back(y);
        edges[y].push_back(x);
    }
    dfs(1,0);
    while(m--)
    {
        l=1;
        r=n;
        read(k);
        while(k--)
        {
            read(x);
            if(x!=1)
            {
                x=fa[x];
            }
            l=max(l,in[x]);
            r=min(r,out[x]);
        }
        if(l<=r)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}

F.Make k Equal

给你一个数组a,每次操作你可以使最大值减一或最小值加一,问经过最少多少次这样的操作后,数组a中有k个值相等

如果数列里面本来就有k个相同的数自然是最好,直接输出0;
其他的情况要从排序后的两端开始,总是要让他们成为距离尾端k的数,但是如果k+1或n-1-k有相同的数,前面就可以偷一点懒,少+或-一次,比如
12344经过几次变换后变为33344,而k+1还有一位相同的,这个时候我们只要另其中两个3变为4即可符合题意
还有一种情况,可以两端都操作,搞成中位数,这时n<2k,还要统计一次两端。
例如:12345搞到最后可以是22344,选两个搞成3个数同

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const ll maxn=2e6+10;
const ll mod=1e9+7;
const ll inf=0x7f7f7f7f;
template<typename T>void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,n,k,l=0,r=0,s=0;
ll a[maxn];
bool flag;
int main()
{
    read(n);
    read(k);
    for(int i=0;i<n;i++)
    {
        read(a[i]);
    }
    sort(a,a+n);
    for(int i=0;i+k-1<n;i++)
    {
        if(a[i]==a[i+k-1])
        {
            printf("0\n");
            return 0;
        }
    }
    for(int i=0;i<k;i++)
    {
        l+=a[k-1]-a[i];
        r+=a[n-1-i]-a[n-k];
    }
    for(int j=k;j<n;j++)
    {
        if(a[k-1]==a[j])
        {
            l--;
        }
        if(a[n-k]==a[n-1-j])
        {
            r--;
        }
    }
    for(int i=0;i<n-1-i;i++)
    {
        s+=a[n-1-i]-a[i];
    }
    printf("%lld\n",min(s-(n-k),min(l,r)));
    return 0;
}
发布了36 篇原创文章 · 获赞 6 · 访问量 4774

猜你喜欢

转载自blog.csdn.net/STL_CC/article/details/105132540