Codeforces Round #545题解

A题

做法很明显,就是隔壁连续1和连续2取min,虽然写的比较复杂

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N];
queue<int> q1,q2; 
int main(){
    int n;
    cin>>n;
    int i;
    int ans=0;
    for(i=1;i<=n;i++){
        cin>>a[i];
    }
    int cnt1=0,cnt2=0;
    int last=0;
    int flag=0;
    for(i=2;i<=n;i++){
        if(a[i-1]!=a[i]){
            if(!flag){
                flag=a[i-1];
            }
            if(a[i-1]==1){
                q1.push(i-1-last);
            }
            else{
                q2.push(i-1-last);
            }
            last=i-1;
        }
    }
    if(a[n]==2){
        q2.push(n-last);
    }
    else{
        q1.push(n-last);
    }
    while(q1.size()&&q2.size()){
        int t1=q1.front();
        int t2=q2.front();
        ans=max(ans,min(t1,t2));
        if(flag==1){
            q1.pop();
            flag=2;
        }
        else{
            flag=1;
            q2.pop();
        }
    } 
    cout<<ans*2<<endl;
    return 0;
} 
View Code

B题

这题如果直接模拟感觉讨论的情况会比较多,因此我们列方程式来做,这也会列出两个等式,我们枚举只会a的个数和每边存在会的人数的总数,这也所有变量都能够被求出来

只有去掉非法情况并判断结果即可,没有则输出-1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N],c[N],n;
vector<int> num[5];
int main(){
    cin>>n;
    int i,j,k;
    int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
    string s;
    cin>>s;
    s=" "+s;
    for(i=1;i<(int)s.size();i++){
        c[i]=(s[i]=='1')?1:0;
    }
    cin>>s;
    s=" "+s; 
    for(i=1;i<(int)s.size();i++){
        a[i]=(s[i]=='1')?1:0;
    }
    for(i=1;i<=n;i++){
        if(c[i]&&!a[i]){
            cnt1++;
            num[1].push_back(i);
        }
        if(!c[i]&&a[i]){
            cnt2++;
            num[2].push_back(i);
        }
        if(c[i]&&a[i]){
            cnt3++;
            num[3].push_back(i);
        }
        if(!c[i]&&!a[i]){
            num[4].push_back(i);
            cnt4++;
        }
    }
    for(i=0;i<=cnt1+cnt3;i++){
        for(j=0;j<=i&&j<=cnt1;j++){
            int tmp=i-j;
            if(tmp<0||tmp>cnt3)
                continue;
            int b=cnt2-2*i+cnt3+j;
            if(b<0||b>cnt2)
                continue;
            int d1=n/2-b-i;
            int d2=n/2-cnt1-cnt2-cnt3+b+i;
            if(d1<0||d1>cnt4)
                continue;
            if(d2<0||d2>cnt4)
                continue;
            if(d1+d2==cnt4){
                for(int k=0;k<j;k++){
                    cout<<num[1][k]<<" ";
                }
                for(int k=0;k<b;k++){
                    cout<<num[2][k]<<" ";
                }
                for(int k=0;k<i-j;k++){
                    cout<<num[3][k]<<" ";
                }
                for(int k=0;k<d1;k++){
                    cout<<num[4][k]<<" ";
                } 
                cout<<endl;
                return 0;
            }
        }
    }
    cout<<-1<<endl;
    return 0;
} 
View Code

C题

这题比B题简单,重新赋值其实相当于找离散化的值,我们又注意到,只有交点对左右两边都有影响,因此取这个交点在行列中离散话较大的值,因为这个交点只能取一个值

显然小的就要变成大的,以此类推,全部平移差值之后取行列max

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e6+10;
int a[1010][1010];
vector<int> row[N];
vector<int> col[N];
int ans[1010][1010];
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    int i,j;
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            cin>>a[i][j];
            row[i].push_back(a[i][j]);
            col[j].push_back(a[i][j]);
        }
    }
    for(i=1;i<=n;i++){
        sort(row[i].begin(),row[i].end());
        row[i].erase(unique(row[i].begin(),row[i].end()),row[i].end());
    }
    for(i=1;i<=m;i++){
        sort(col[i].begin(),col[i].end());
        col[i].erase(unique(col[i].begin(),col[i].end()),col[i].end());
    }
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            int pos1=lower_bound(row[i].begin(),row[i].end(),a[i][j])-row[i].begin()+1;
            int pos2=lower_bound(col[j].begin(),col[j].end(),a[i][j])-col[j].begin()+1;
            int mx;
            if(pos1>pos2){
                mx=(int)col[j].size()+pos1-pos2;
                ans[i][j]=max(mx,(int)row[i].size());
            }
            else{
                mx=(int)row[i].size()+pos2-pos1;
                ans[i][j]=max(mx,(int)col[j].size());
            }
        }
    }
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            cout<<ans[i][j]<<" ";
        }
        cout<<endl;
    }
}
View Code

D题

贪心思路,因为要求出现次数最多,所以除去非法情况,我们刚开始直接生成一个t一定不劣

那么之后我们发现,只要找到t串前后缀最大的地方,这样是最优的,因为可以用最小的代价又产生一个t串,那么这个其实就是kmp算法。

之后就是不停循环构造直到字符不够

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e6+10;
int ne[N];
int main(){
    ios::sync_with_stdio(false);
    string s,t;
    cin>>s>>t;
    int i,j;
    int cnt1=0,cnt0=0;
    if(t.size()>s.size()){
        cout<<s<<endl;
        return 0;
    }
    s=" "+s;
    t=" "+t;
    string res=" ";
    for(i=1;i<(int)s.size();i++){
        if(s[i]=='1')
            cnt1++;
        else
            cnt0++;
    }
    int flag=0;
    for(i=1;i<(int)t.size();i++){
        if(t[i]=='1'){
            if(cnt1){
                res+=t[i];
                cnt1--;
            }
            else{
               flag=1;
            }
        }
        else{
            if(cnt0){
                res+=t[i];
                cnt0--;
            }
            else{
                flag=1;
            }
        }
    }
    if(flag){
        cout<<s.substr(1)<<endl;
        return 0;
    }
    for(i=2,j=0;i<(int)t.size();i++){
        while(j&&t[i]!=t[j+1]){
            j=ne[j];
        }
        if(t[j+1]==t[i]){
            j++;
        }
        ne[i]=j;
    }
    int pos=ne[(int)t.size()-1]+1;
    flag=0;
    while(1){
        for(i=pos;i<(int)t.size();i++){
            if(t[i]=='1'){
                if(cnt1){
                    res+=t[i];
                    cnt1--;
                }
                else{
                    flag=1;
                    break;
                }
            }
            else{
                if(cnt0){
                    res+=t[i];
                    cnt0--;
                }
                else{
                    flag=1;
                    break;
                }
            }
        }
        if(flag)
            break;
        pos=ne[(int)t.size()-1]+1;
    }
    while(cnt1--){
        res+='1';
    }
    while(cnt0--){
        res+='0';
    }
    cout<<res.substr(1);
}
View Code

E题

本题思路比较巧妙,首先要观察的一点是,每个点都能被看成d个点,表示每个天数,这是根据我们的题目发现天数很少可以看出来

那么接下来考虑如何转移,这时候我们发现因为有环,所以不能直接跑,一般环问题我们都会转化成缩点变成dag问题,这题也不例外,只要缩完点,那么一个连通分量里能走到的点的权值肯定是已知的

之后就是去跑最长路即可,用这种办法写很卡空间,很不幸,我没卡过去,这里会MLE在73个点,建议观看别人的代码卡空间,有空我再调一调

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=100005*50;
int n,m,d;
int h[N],ne[N],e[N],idx;
int dfn[N],low[N],times;
stack<int> q,tmp;
ll dis[200100];
int scnt,id[N];
int vis[N],ins[N];
int f[N];
int val[N];
int h1[N],ne1[N],e1[N],idx1;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void add1(int a,int b){
    e1[idx1]=b,ne1[idx1]=h1[a],h1[a]=idx1++;
}
int get(int i,int j){
    return j*n+i;
}
void tarjan(int u){
    dfn[u]=low[u]=++times;
    q.push(u);
    ins[u]=1;
    int i;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(!dfn[j]){
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(ins[j]){
            low[u]=min(low[u],dfn[j]);
        }
    }
    if(dfn[u]==low[u]){
        ++scnt;
        while(1){
            int t=q.top();
            q.pop(),ins[t]=0;
            id[t]=scnt;
            int x,y;
            x=(t-1)%n+1,y=(t-1)/n;
            if(!vis[x]&&((dis[x]>>y)&1)){
                val[scnt]++;
                vis[x]=1;
                tmp.push(x);
            }
            if(t==u)
            break;
        }
    }
    while(tmp.size()){
        auto t=tmp.top();
        tmp.pop();
        vis[t]=0;
    }
}
int dfs(int u){
    if(vis[u])return f[u];
    vis[u]=1;
    for(int i=h1[u];i!=-1;i=ne1[i]){
        int v=e1[i];
        f[u]=max(f[u],dfs(v));
    }
    return f[u]+=val[u];
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>d;
    int i,j;
    memset(h,-1,sizeof h);
    memset(h1,-1,sizeof h1);
    for(i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        for(j=0;j<=d-1;j++){
            add(get(u,j),get(v,(j+1)%d));
        }
    }
    for(i=1;i<=n;i++){
        string s;
        cin>>s;
        for(j=0;j<d;j++){
            dis[i]|=1ll*(s[j]-'0')<<j;
        }
    }
    tarjan(1);
    for(i=1;i<=n*d;i++){
        if(!dfn[i])continue;
        int u=id[i];
        for(int j=h[i];j!=-1;j=ne[j]){
            int v=e[j];
            if(!dfn[v])
                continue;
            v=id[v];
            if(u!=v){
                add1(u,v);
            }
        }
    }
    cout<<dfs(id[1])<<endl;
}
View Code

F题

交互题,使用floyd消圈法,因为不太想写交互题,所以这题就略过了

posted @ 2020-12-16 23:38  朝暮不思  阅读(69)  评论(0编辑  收藏  举报