Codeforces Round #541 (Div. 2)(A,B,C,D,E,F)

A. Sea Battle

题意:询问两个长方形的外围周长,如图中所示

    注:两个长方形左侧对齐

简单题,已AC,代码如下

#include<bits/stdc++.h>

using namespace std;
int a,b,c,d;
int main()
{
    scanf("%d%d%d%d",&a,&b,&c,&d);
    int ans=(b+d)*2+a+c+4;
    ans+=max(a+1,c+1)-min(a+1,c+1);
    printf("%d",ans);
    return 0;
}

 

 

B. Draw!

题意:给出比赛过程中部分出现的比分,问有几次平分的时候

    注:0:0也算一次

简单题,已AC,代码如下

#include<bits/stdc++.h>
using namespace std;
const int maxn=101000;
int n,a[maxn],b[maxn];
int main()
{
    scanf("%d",&n);
    a[0]=0;a[1]=0;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        if(b[i-1]>=a[i-1]&&b[i-1]<=a[i])
            ans+=min(a[i],b[i])-b[i-1]+1;
        else if(a[i-1]>=b[i-1]&&a[i-1]<=b[i])
            ans+=min(a[i],b[i])-a[i-1]+1;
        if(a[i-1]==b[i-1]&&i!=1) ans--;
    }
    printf("%d",ans);
    return 0;
}

 

 

C. Birthday

题意:给出n个人的身高,让他们围成一圈,是相邻两人最大差值最小

题解:排序,让身高   矮------>高---------->矮

简单题,已AC,代码如下

#include<bits/stdc++.h>
using namespace std;
int n,a[110];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int i;
    for(i=1;i<=n;i+=2)
        printf("%d ",a[i]);
    for(i=n-n%2;i;i-=2)
        printf("%d ",a[i]);
    return 0;
}

 

 

 

D. Gourmet choice

题意:给出矩阵,i行j列表示a[i]和b[j]的关系,询问这种关系是否成立,成立则输出一种可能结果,并使得最大的数最小

题解:相等的用并查集,然后用拓扑排序从大的指向小的

已AC,代码如下

代码写的丑,敬请谅解

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2010;
struct edge{
    int to,nxt;
}e[maxn*maxn/2];
int head[maxn],cnt;
int mp[maxn][maxn],vis[maxn],fa[maxn];
void add(int u,int v){
    e[++cnt].to=v; e[cnt].nxt=head[u];
    head[u]=cnt;
}
int pre[maxn<<1],in[maxn],dep[maxn];
queue<int>que;
int Find(int x){
    return x==pre[x] ? x:pre[x]=Find(pre[x]);
}
void join(int x,int y){
    int p=Find(x),q=Find(y);
    if(p<q) swap(p,q);
    if(p!=q) pre[p]=q;
}
int n,m;
char s[maxn][maxn];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+m;i++) pre[i]=i;
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;j++){
            if(s[i][j]=='=') join(i,j+n);
        }
    }
    for(int i=1;i<=n+m;i++){
        fa[i]=Find(i);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i][j]=='=') continue;
            if(fa[i]==fa[j+n]){
                puts("No");
                return 0;
            }
            if(s[i][j]=='>'){
                if(mp[fa[i]][fa[j+n]]) continue;
                add(fa[i],fa[j+n]);
                in[fa[j+n]]++;
                mp[fa[i]][fa[j+n]]=1;
            }
            if(s[i][j]=='<'){
                if(mp[fa[j+n]][fa[i]]) continue;
                add(fa[j+n],fa[i]);
                in[fa[i]]++;
                mp[fa[j+n]][fa[i]]=1;
            }
        }
    }
    set<int>st;
    for(int i=1;i<=n+m;i++){
        if(in[fa[i]]==0&&i==fa[i]){
                que.push(fa[i]);
                dep[fa[i]]=1;
                vis[fa[i]]=1;
        }
        st.insert(fa[i]);
    }
    int maxx=1,cnt=st.size();
    while(que.size()){
        int p=que.front();
        cnt--;
        que.pop();
        for(int i=head[p];i;i=e[i].nxt){
            int v=e[i].to;
            if(--in[v]==0){
                que.push(v);
                dep[v]=dep[p]+1;
                maxx=max(maxx,dep[v]);
            }
        }
    }
    if(cnt>0){
        puts("No");
        return 0;
    }
    puts("Yes");
    for(int i=1;i<=n;i++){
        printf("%d ",maxx-dep[fa[i]]+1);
    } printf("\n");
    for(int i=n+1;i<=n+m;i++){
        printf("%d ",maxx-dep[fa[i]]+1);
    } printf("\n");
    return 0;
}

 

 

 

E. String Multiplication

题意:将后一个字符串插入前一个字符串中,询问结果串中最长的连续相同子串

    注:插入方式     t+s1+t+s2+…+t+sm+t

                                 s="abc"     t= "de"            "deadebdecde"

题解:动态规划   dp[i][j] 输入第i个子串后,字母j最长子串有多长

            只有t串的前后缀才会累积上一个串的结果

             每次循环记录三种状态   1、t是否只由一个字母组成

                                                        2、t最前面的相同字母有几个

                                                        3、t最后面的相同字母有几个

已AC,代码如下

#include<bits/stdc++.h>
using namespace std;
char s[101000];
int n,dp[101000][30];
int main()
{
    scanf("%d",&n);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=26;j++)
            if(dp[i-1][j]) dp[i][j]=1;//初始化
        int l=1,r=1,a=0,b=0,c=0,x=0,y=0;
        int m=strlen(s+1);
        for(;r<=m;l=r+1,r=l)
        {
            int u=s[l]-'a'+1;
            while(r<m&&s[l]==s[r+1]) r++;
            dp[i][u]=max(dp[i][u],r-l+1);
            if(l==1&&r==m) a=u;
            if(l==1) {b=u;x=r-l+1;}
            if(r==m) {c=u;y=r-l+1;}
        }
        if(a) dp[i][a]=max(dp[i][a],(dp[i-1][a]+1)*m+dp[i-1][a]);//都由一个字母组成
        if(dp[i-1][b]) dp[i][b]=max(dp[i][b],1+x);//前缀字母产生的影响
        if(dp[i-1][c]) dp[i][c]=max(dp[i][c],1+y);//后缀字母产生的影响
        if(b==c&&dp[i-1][b]) dp[i][b]=max(dp[i][b],1+x+y);//如果前后缀字母相同,影响累加
    }
    int ans=0;
    for(int i=1;i<=26;i++)
        ans=max(ans,dp[n][i]);
    printf("%d",ans);
    return 0;
}

                             

 

 

 

F. Asya And Kittens

题意:最开始每个数在各自的集合中,每次只能合并相邻两个集合(给出两个集合中的任意数字),n个数经过n-1次合并,在同一集合中,问原始是什么样子          

题解:用并查集,两个数组pre[i],bac[i],pre[i]保存i所在集合最前面的数是什么,bac[i]保存i所在集合最后面的数是什么

注:因为需要压缩路径,所以还需用一个数组保存答案

  已AC,代码如下      



#include<bits/stdc++.h>
using namespace std;
int n,m,pre[151000],a,b,ans[151000],bac[151000];
int Find_pre(int x)
{
    int p,a;
    p=x;
    while(x!=pre[x]) x=pre[x];
    while(p!=x)
    {
        a=pre[p];
        pre[p]=x;
        p=a;
    }
    return x;
}
int Find_bac(int x)
{
    int p,a;
    p=x;
    while(x!=bac[x]) x=bac[x];
    while(p!=x)
    {
        a=bac[p];
        bac[p]=x;
        p=a;
    }
    return x;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {pre[i]=i;bac[i]=i;}
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        int p=Find_pre(b);
        int q=Find_bac(a);
        pre[p]=q;bac[q]=p;
        ans[q]=p;
    }
    int key=-1;
    for(int i=1;i<=n;i++)
        if(pre[i]==i) key=i;
    for(int i=1;i<=n;i++)
    {
        printf("%d ",key);
        key=ans[key];
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值