Codeforces Round 607 Div2

round 607

A

题意

根据后缀判断出自哪种语言

思路

水题

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=1e3+3;

char s[MAX];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s",s);
        int len=strlen(s);
        if(s[len-2]=='p'&&s[len-1]=='o')
        {
            printf("FILIPINO\n");
            continue;
        }
        if(s[len-4]=='d'&&s[len-3]=='e'&&s[len-2]=='s'&&s[len-1]=='u')
        {
            printf("JAPANESE\n");
            continue;
        }
        if(s[len-4]=='m'&&s[len-3]=='a'&&s[len-2]=='s'&&s[len-1]=='u')
        {
            printf("JAPANESE\n");
            continue;
        }
        if(s[len-5]=='m'&&s[len-4]=='n'&&s[len-3]=='i'&&s[len-2]=='d'&&s[len-1]=='a')
        {
            printf("KOREAN\n");
            continue;
        }
    }
}

B

题意

给两个字符串a,ba可以交换任意一对字符(只能交换一次),问能否使得a字典序小于b

思路

贪心,越小的字符越前则越好,处理一下后缀min,然后从前往后判断能否交换就好了。这样一定是最优的,交换完了以后比较一下输出结果。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=5e3+3;

char s[MAX],c[MAX],minn[MAX];
int index[MAX];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s%s",s,c);
        int lens=strlen(s);
        minn[lens-1]=s[lens-1];
        index[lens-1]=lens-1;
        for(int i=lens-2; i>0; i--)
        {
            index[i]=index[i+1];
            minn[i]=minn[i+1];
            if(s[i]<minn[i+1])
            {
                index[i]=i;
                minn[i]=s[i];
            }
        }
        for(int i=0; i<lens-1; i++)
            if(s[i]>minn[i+1])
            {
                swap(s[i],s[index[i+1]]);
                break;
            }
        if(strcmp(s,c)<0)
            printf("%s\n",s);
        else
            printf("---\n");
    }
}

C

题意

给一个字符串,由1,2,3组成。然后模拟一个光标,每次操作光标向右移动一位,然后把光标左右字符串切开成slsr,然后把srsl后粘贴【sl的最后一位】次。问操作x次之后此字符串的长度,输出对1e9+7取模。

思路

看起来好像是找规律,但是实际上暴力模拟就行了。因为每次操作只向右移动一位,所以总共需要记录的字符不超过x个。所以模拟复杂度O(x)

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=2e6+6;
const int mod=1e9+7;

char s[MAX];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int x;
        scanf("%d%s",&x,s+1);
        int len=strlen(s+1);
        int res=len;
        for(int i=1; i<=x; i++)
        {
            if(s[i]=='1')continue;
            int cnt=s[i]-'1';
            int cur=(res-i+mod)%mod;
            if(len<x)
            {
                len+=cur;
                for(int j=1;j<=cnt;j++)
                    for(int k=i+1; k<=len&&k+j*cur<=x; k++)
                        s[k+j*cur]=s[k];
            }
            res=((res+cur*cnt*1ll)%mod+mod)%mod;
        }
        printf("%d\n",(res+mod)%mod);
    }
}

D

题意

给一个字符矩阵,由A,P构成。每次操作可以选1×K的一段或K×1的一段,然后向上下或左右扩展任意长度,使得扩展的那段也变成和选择的那段一样,求最少多少次可以把整个矩阵全变成A

思路

显然,若答案存在,则在[0,4]之间。然后先按行再按列判断一下就好了,先判是不是整行/列,然后判是不是在边上…………,计算答案取min即可。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=66;

char G[MAX][MAX];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,m,res=MAX,cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            scanf("%s",G[i]);
        for(int i=0; i<n; i++)
        {
            bool flag1=1,flag2=0;
            for(int j=0; j<m; j++)
            {
                flag1&=(G[i][j]=='A');
                flag2|=(G[i][j]=='A');
                cnt+=(G[i][j]=='A');
            }
            if(flag1)
            {
                if(i==0||i==n-1)
                    res=min(res,1);
                else
                    res=min(res,2);
            }
            else
            {
                if(!flag2)continue;
                if(G[i][0]=='A'||G[i][m-1]=='A')
                {
                    if(i==0||i==n-1)
                        res=min(res,2);
                    else
                        res=min(res,3);
                }
                else
                {
                    if(i==0||i==n-1)
                        res=min(res,3);
                    else
                        res=min(res,4);
                }
            }
        }
        if(cnt==n*m)
        {
            printf("0\n");
            continue;
        }
        for(int j=0; j<m; j++)
        {
            bool flag1=1,flag2=0;
            for(int i=0; i<n; i++)
            {
                flag1&=(G[i][j]=='A');
                flag2|=(G[i][j]=='A');
            }
            if(flag1)
            {
                if(j==0||j==m-1)
                    res=min(res,1);
                else
                    res=min(res,2);
            }
            else
            {
                if(!flag2)continue;
                if(G[0][j]=='A'||G[n-1][j]=='A')
                {
                    if(j==0||j==m-1)
                        res=min(res,2);
                    else
                        res=min(res,3);
                }
                else
                {
                    if(j==0||j==m-1)
                        res=min(res,3);
                    else
                        res=min(res,4);
                }
            }
        }
        if(res==MAX)
            printf("MORTAL\n");
        else
            printf("%d\n",res);
    }
}

E

题意

给一棵带权树,2k个节点,将k对人分配到此树的节点上,求分配后每一对人两者距离之和的最大值和最小值。

思路

可以想到最大值就要每一对的两个人尽量远,最小值就是两个人尽量近。所以先求出树的重心,记为rt。则可以认为rt将树分为左右两部分(不一定是两子树),两者节点数相差1。在此模型上考虑。

最大值就是左边的全部与右边的配对,不与自己部分的配对,可以发现最大值就是所有节点到rt的距离之和。

扫描二维码关注公众号,回复: 9340055 查看本文章

最小值就是每一部分尽量自给自足。则可以想到:从rt出发开始遍历,如果子树的节点个数为偶数,那么自给自足一定优于连边到rt,所以连到此子树的边权一定没有贡献。如果子树的节点数为奇数,那么一定无法自给自足,那么此子树一定要连到rt上。然后问题可以分解成子问题。每个子问题求一个节点x的所有子树的贡献。边界为叶子节点,叶子节点一定要连到父亲节点上,也符合奇偶规律。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=2e5+5;
typedef long long ll;

struct Edge
{
    int to,val,nxt;
}edges[MAX<<1];
int head[MAX],siz[MAX],mx_son_siz[MAX],n,tot,rt;
ll minn,maxx;

inline void addedge(int u,int v,int w)
{
    edges[tot].to=v;
    edges[tot].val=w;
    edges[tot].nxt=head[u];
    head[u]=tot++;
}

void getroot(int x,int fa)
{
    siz[x]=1;
    mx_son_siz[x]=0;
    for(int i=head[x];i!=-1;i=edges[i].nxt)
    {
        int v=edges[i].to;
        if(v==fa)continue;
        getroot(v,x);
        siz[x]+=siz[v];
        mx_son_siz[x]=max(mx_son_siz[x],siz[v]);
    }
    mx_son_siz[x]=max(mx_son_siz[x],n-siz[x]);
    if(!rt||mx_son_siz[x]<mx_son_siz[rt])
        rt=x;
}

void dfs(int x,int fa,ll sum,int w)
{
    siz[x]=1;
    for(int i=head[x];i!=-1;i=edges[i].nxt)
    {
        int v=edges[i].to;
        if(v==fa)continue;
        dfs(v,x,sum+edges[i].val,edges[i].val);
        siz[x]+=siz[v];
    }
    if(siz[x]&1)
        minn+=w;
    maxx+=sum;
}

void init()
{
    for(int i=1;i<=n;i++)
        head[i]=-1;
    rt=tot=0;
    minn=maxx=0ll;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        n<<=1;
        init();
        for(int i=1;i<n;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        getroot(1,-1);
        dfs(rt,-1,0,0);
        printf("%I64d %I64d\n",minn,maxx);
    }
}

猜你喜欢

转载自www.cnblogs.com/cryingrain/p/12348072.html
今日推荐