codeforces 541 div2

A. Sea Battle

题意

给两个矩形堆在一起,大的在下,小的在上,左边界对齐,求整个图形的外延有多少格。如图一在这里插入图片描述
答案显然就是最长的宽x2+两个矩形的高x2+4

B. Draw!

题意

给出部分足球比赛的比分,每次进求,赢得一方比分只能加1,可能出现多次相同的比分,最后一个比分为最终得分。求比赛期间出现平局情况的最多次数(就是比分相同的情况)。

思路

先预处理一下,把重复的比分去掉。对于相邻两次比分,(a[i],b[i])—>(a[i+1],b[i+1])期间可能出现最多平局的次数就是线段【a[i],a[i+1]】与【b[i],b[i+1]】的交集的大小。注意一个坑点就是如果a[i]==b[i],那么a[i]这个点会被前后重复计算,所以要减一。但是对于最后的ans要加1,因为(0,0)的时候没有被多算.

代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
int n;
int a[maxn][2],b[maxn][2],tot;
int calc(int x1,int y1,int x2,int y2)
{
    if(x1>x2){
        swap(x1,x2);
        swap(y1,y2);
    }
    if(y1>=x2&&y1<=y2)return y1-x2+1;
    else if(y1>y2)return y2-x2+1;
    else return 0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i][0],&a[i][1]);
    for(int i=1;i<=n;i++){
        if(a[i][0]==a[i-1][0]&&a[i][1]==a[i-1][1])continue;
        else {
            b[++tot][0]=a[i][0];
            b[tot][1]=a[i][1];
        }
    }
    int ans=0;
    for(int i=1;i<=tot;i++){
        ans+=calc(b[i-1][0],b[i][0],b[i-1][1],b[i][1]);
        if(b[i-1][0]==b[i-1][1])ans--;
        //printf("ans = %d\n",ans);
    }
    printf("%d\n",++ans);
    return 0;
}

C. Birthday

题意

给n个不同高度的人排一下队,且排成一个环形。要使相邻两个人的高度差的最大值最小。

思路

求最大的最小,一般都可以二分。这里可以直接排序,对于第一个人,将其余比他高的人依次放在他左右两侧即可。

代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
int n;
int a[maxn];
int b[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int mid=1000;
    int l=mid,r=mid;
    b[mid]=a[1];
    for(int i=2;i<=n;i++){
        if(i%2==0)b[++r]=a[i];
        else b[--l]=a[i];
    }
    for(int i=l;i<=r;i++)printf("%d%c",b[i],i==r?'\n':' ');
    return 0;
}

D. Gourmet choice

题意

一个美食家第一天吃了n中美食,第二天吃了m种。他画了一个nxm的表格来表示他们之间好吃程度的大小关系。a[i][j]=’>‘表示i比j好吃。a[i][j]=’<‘表示j比i好吃。a[i][j]=’='表示i,j的好吃程度一样。现在要你给所有的菜打个分数。使得满足该表中的所有关系,并且要求最高的分数越小越好。

思路

对于’=‘的关系先建图,搜连通块,缩点。对于’<‘和’>‘关系再建一个有向图,方向由低级的指向高级;例如a[u][v]=’>’ ,v==>u;然后将所有入度为0的点入度,设dis[u]=1;
然后类似跑一遍spfa,找出最远的点。

代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 2005
int n,m;
char s[maxn][maxn];
int col[maxn],color;
vector<int>c[maxn];
vector<int>e[maxn],ne[maxn];
bool vis[maxn],inq[maxn];
int dis[maxn],du[maxn],cnt[maxn];
void dfs(int x)
{
    vis[x]=1;
    col[x]=color;
    c[color].push_back(x);
    for(int i=0;i<e[x].size();i++){
        int v=e[x][i];
        if(vis[v]==0){
            dfs(v);
        }
    }
    return ;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i][j]=='='){
                e[i].push_back(n+j);
                e[n+j].push_back(i);
            }
        }
    }
    for(int i=1;i<=n+m;i++){
        if(vis[i]==0){
            ++color;
            dfs(i);
        }
    }
    bool flag=0;
    for(int i=1;i<=n;i++){
        if(flag)break;
        for(int j=1;j<=m;j++){
            if(flag)break;
            if(s[i][j]=='<'){
                if(col[i]!=col[n+j]){
                    ne[col[i]].push_back(col[n+j]);
                    du[col[n+j]]++;
                }
                else flag=1;
            }
            else if(s[i][j]=='>'){
                if(col[i]!=col[n+j]){
                    ne[col[n+j]].push_back(col[i]);
                    du[col[i]]++;
                }
                else flag=1;
            }
        }
    }
    if(flag){
        printf("No\n");
        return 0;
    }
    queue<int>q;
    for(int i=1;i<=color;i++){
        if(du[i]==0){
            q.push(i);
            inq[i]=1;
            dis[i]=1;
        }
    }
    int ma=0;
    while(!q.empty()){
        int u=q.front();q.pop();inq[u]=0;
        cnt[u]++;
        if(cnt[u]>=n+m){
            flag=1;
            break;
        }
        ma=max(ma,dis[u]);
        for(int i=0;i<ne[u].size();i++){
            int v=ne[u][i];
            if(dis[v]==0){
                q.push(v);
                dis[v]=dis[u]+1;
            }
            else if(dis[v]<dis[u]+1){
                dis[v]=dis[u]+1;
                if(inq[v]==0){
                    inq[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(flag){
        printf("No\n");
        return 0;
    }
    printf("Yes\n");
    for(int i=1;i<=n;i++)printf("%d%c",dis[col[i]],i==n?'\n':' ');
    for(int i=1;i<=m;i++)printf("%d%c",dis[col[i+n]],i==m?'\n':' ');
    return 0;
}

E. String Multiplication

题意

定义字符串S∗T=T+S1(第一个字母)+T+…+Sn+TS∗T=T+S1(第一个字母)+T+…+Sn+T ST=T+S_1(第一个字母)+T+…+S_n+TS∗T=T+S1​(第一个字母)+T+…+Sn​+T,例如ac∗b=babcbac∗b=babcb acb=babcbac∗b=babcb,现在给出n个串P1…PnP1…Pn P_1…P_nP1​…Pn​,求目标串(…(P1∗P2)∗P3)…)∗Pn(…(P1∗P2)∗P3)…)∗Pn (…(P_1*P_2)*P_3)…)*P_n(…(P1​∗P2​)∗P3​)…)∗Pn​中,连续相同字符的个数的最大值(abbbc=3abbbc=3 abbbc=3abbbc=3)。
(参考博客
https://blog.csdn.net/jk_chen_acmer/article/details/87904929

思路

枚举26个字母的最长长度,然后取最大。对于每一个字母,s[i].L表示第i个字符串的前缀最多有多少个该字母,s[i].R表示其后缀最多有多少个该字母,s[i].ma表示第i个串中包含连续的该字符的最长长度。
如果s[i]全是由该字符组成,那么dp[i]=dp[i-1]+dp[i-1]*strlen(s[i])
如果dp[i-1]!=0,dp[i]=max(s[i].ma,s[i].L+s[i].R+1)
如果dp[i-1]==0,dp[i]=s[i].ma;

代码

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
int n;
string s[maxn];
struct node{
    int l,r,mid;
    bool isall;
};
node a[maxn][30];
int dp[maxn][30];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>s[i];
    }
    //for(int i=1;i<=n;i++)cout<<s[i]<<endl;
    for(int i=1;i<=n;i++){
        int len=s[i].size();
        for(int j=0;j<26;j++){
            for(int k=0;k<len;k++){
                if('a'+j==s[i][k])a[i][j].l++;
                else break;
            }
            for(int k=len-1;k>=0;k--){
                if('a'+j==s[i][k])a[i][j].r++;
                else break;
            }
            int temp=0;
            for(int k=0;k<len;k++){
                if('a'+j==s[i][k])temp++;
                else{
                    a[i][j].mid=max(a[i][j].mid,temp);
                    temp=0;
                }
            }
            a[i][j].mid=max(a[i][j].mid,temp);///最后记得判断一次 因为可能结尾满足 经常有这种bug
            if(temp==len)a[i][j].isall=1;
        }
    }
    /*for(int i=1;i<=n;i++){
        printf("--------------i = %d:\n",i);
        for(int j=0;j<26;j++){
            printf("%3d: l = %d r = %d mid = %d isall = %d\n",j,a[i][j].l,a[i][j].r,a[i][j].mid,a[i][j].isall);
        }

    }*/
    for(int i=0;i<26;i++){
        for(int j=1;j<=n;j++){
            if(a[j][i].isall)dp[j][i]=dp[j-1][i]+(dp[j-1][i]+1)*a[j][i].mid;
            else if(dp[j-1][i]!=0)dp[j][i]=max(a[j][i].mid,a[j][i].l+a[j][i].r+1);
            else if(dp[j-1][i]==0)dp[j][i]=a[j][i].mid;
        }
    }
    int ans=0;
    for(int i=0;i<26;i++)ans=max(ans,dp[n][i]);
    printf("%d\n",ans);
    return 0;
}

F. Asya And Kittens

题意

有一个长度为n的序列,进行了n-1次合并操作,终于变成了一个区域。每次合并只能选择相邻两个区域内的数进行。给出合并顺序,要求还原出原序列。

思路

用两个并查集维护每个数字所在区间的最左点和最右点。每次选择两个数字合并的时候,就将他们的最右点和最左点连起来,同时更新并查集。最后将链条从头搜到尾即可。

代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 150005
int n;
vector<int>e[maxn];
int du[maxn];
int king1[maxn],king2[maxn];
vector<int>ans;
void init()
{
    for(int i=0;i<maxn;i++)king1[i]=king2[i]=i;
}
int getfa1(int x){return king1[x]==x?x:king1[x]=getfa1(king1[x]);}///最前面的值
int getfa2(int x){return king2[x]==x?x:king2[x]=getfa2(king2[x]);}///最后面的值
int main()
{
    init();
    scanf("%d",&n);
    for(int i=1,x,y;i<=n-1;i++){
        scanf("%d%d",&x,&y);
        int tx=getfa2(x);
        int ty=getfa1(y);
        king1[ty]=tx;
        king2[tx]=ty;
        e[tx].push_back(ty);
        du[ty]++;
    }
    int s=0;
    for(int i=1;i<=n;i++){
        if(du[i]==0){
            s=i;
            break;
        }
    }
    int i;
    for(i=s;e[i].size();i=e[i][0]){
        printf("%d ",i);
    }
    printf("%d\n",i);
    return 0;
}

G. Most Dangerous Shark

单调栈优化dp—待补
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值