Codeforces Round #568题解

第一次遇到有9题的div2。。。

A题

排序后,伸展两边

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
const int mod=1e9+7;
ll a[4];
int main(){
    ios::sync_with_stdio(false);
    ll d;
    cin>>a[1]>>a[2]>>a[3]>>d;
    sort(a+1,a+4);
    ll ans=0;
    ans+=max(0ll,d-a[2]+a[1]);
    ans+=max(0ll,d-a[3]+a[2]);
    cout<<ans<<endl;
    return 0;
}
View Code

B题

写了个臭暴力,因为输入的是按序的,所以一位一位匹配,当不同了,看看B有没有机会变成和当前的一样的,其实就是越过中间相等的部分

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
const int mod=1e9+7;
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        string a,b;
        cin>>a>>b;
        int i,j;
        int flag=0;
        for(i=0,j=0;i<a.size()&&j<b.size();){
            if(a[i]==b[j]){
                i++,j++;
            }
            else{
                int tmp=j;
                while(j<b.size()&&b[j]==b[j-1]){
                    j++;
                }
                if(tmp==j){
                    flag=1;
                    break;
                }
            }
        }
        if(flag){
            cout<<"NO"<<endl;
        }
        else{
            if(i!=a.size()){
                flag=1;
            }
            j--;
            for(i=j+1;i<b.size();i++){
                if(b[i]!=b[j]){
                    flag=1;
                    break;
                }
            }
            if(flag){
                cout<<"NO"<<endl;
            }
            else{
                cout<<"YES"<<endl;
            }
        }
    }
    return 0;
}
View Code

C题

分为两个version,直接讲hard,这题就是当前数必取,之后能在M范围内前面的数取的越多越好

不难想到使用优先队列,但是过了这个数后,这个数不一定要取,因此维护一个对顶堆,先让当前满足条件,然后把数加回来

有个很重要的点是,权值不大于100,因此每次操作不大于100次

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
const int mod=1e9+7;
int a[N];
ll sum[N];
int ans[N];
priority_queue<int> q;
priority_queue<int,vector<int>,greater<int>> p;
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    int i;
    for(i=1;i<=n;i++){
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
    }
    ll tot=0;
    for(i=1;i<=n;i++){
        p.push(a[i]);
        while(tot+a[i]>m){
            int tmp=q.top();
            q.pop();
            p.push(tmp);
            tot-=tmp;
        }
        ans[i]=i-q.size()-1;
        while(p.size()){
            int tmp=p.top();
            if(tot+tmp<=m){
                tot+=tmp;
                p.pop();
                q.push(tmp);
            }
            else{
                break;
            }
        }
        int tmp=a[i];
    }
    for(i=1;i<=n;i++){
        cout<<ans[i]<<" ";
    }
    cout<<endl;
    return 0;
}
View Code

D题

先排序

维护一个map,因为权值相等,就是相当于要不只有一个树,要不只有一种差值,因此我们枚举哪个差值要删除,然后看有没有合适情况

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
const int mod=1e9+7;
int a[N];
int b[N];
map<ll,int> m1;
map<ll,int> pos;
int main(){
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int i;
    for(i=1;i<=n;i++){
        cin>>a[i];
        pos[a[i]]=i;
    }
    sort(a+1,a+1+n);
    for(i=2;i<=n;i++){
        b[i]=a[i]-a[i-1];
    }
    for(i=2;i<=n;i++){
        m1[b[i]]++;
    }
    int flag=0;
    for(i=1;i<=n;i++){
        if(i==1){
            int tmp=a[2]-a[1];
            m1[tmp]--;
            if(m1[tmp]==0){
                m1.erase(tmp);
            }
            if(m1.size()==0||m1.size()==1){
                flag=1;
                cout<<pos[a[1]]<<endl;
                break;
            }
            m1[tmp]++;
        }
        else if(i==n){
            int tmp=a[n]-a[n-1];
            m1[tmp]--;
            if(m1[tmp]==0){
                m1.erase(tmp);
            }
            if(m1.size()==0||m1.size()==1){
                flag=1;
                cout<<pos[a[n]]<<endl;
                break;
            }
            m1[tmp]++;
        }
        else{
            int f1=a[i]-a[i-1];
            int f2=a[i+1]-a[i];
            int f3=a[i+1]-a[i-1];
            m1[f1]--;
            m1[f2]--;
            m1[f3]++;
            if(m1[f1]==0){
                m1.erase(f1);
            }
            if(m1[f2]==0){
                m1.erase(f2);
            }
            if(m1.size()==0||m1.size()==1){
                flag=1;
                cout<<pos[a[i]]<<endl;
                break;
            }
            m1[f1]++;
            m1[f2]++;
            m1[f3]--;
            if(m1[f3]==0){
                m1.erase(f3);
            }
        }
    }
    if(!flag){
        cout<<-1<<endl;
    }
    return 0;
}
View Code

E题

暴力题

首先把每个字母所有的位置存下来,然后从小到大枚举,如果没有,那就取最后一个字母的随便一个位置,因为这个位置一定是不被覆盖了

如果一个,那就这个位置,如果有多个,那就枚举这个字母的位置看是否符合情况

最后check一遍看是否和原来一样

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=5e5+10;
const int mod=1e9+7;
struct node{
    int x,y;
};
struct Node{
    int a,b,c,d;
};
vector<node> pos[2020];
vector<Node> ans;
int a[2020][2020];
int b[2020][2020];
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        ans.clear();
        int n,m;
        cin>>n>>m;
        int i,j,k;
        for(i=0;i<=26;i++){
            pos[i].clear();
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                a[i][j]=0;
                b[i][j]=0;
            }
        }
        int mx=0;
        for(i=1;i<=n;i++){
            string s;
            cin>>s;
            s=" "+s;
            for(j=1;j<=m;j++){
                if(s[j]=='.')
                    continue;
                a[i][j]=s[j]-'a'+1;
                pos[a[i][j]].push_back({i,j});
                mx=max(mx,a[i][j]);
            }
        }
        int flag=0;
        for(i=1;i<=mx;i++){
            if(pos[i].size()==0){
                int x=pos[mx][0].x,y=pos[mx][0].y;
                ans.push_back({x,y,x,y});
            }
            else if(pos[i].size()==1){
                int x=pos[i][0].x,y=pos[i][0].y;
                ans.push_back({x,y,x,y});
            }
            else{
                int x1=pos[i][0].x,y1=pos[i][0].y;
                int x2=pos[i][1].x,y2=pos[i][1].y;
                if(x1!=x2&&y1!=y2){
                    flag=1;
                    break;
                }
                if(x1==x2){
                    for(auto x:pos[i]){
                        if(x.x!=x1){
                            flag=1;
                            break;
                        }
                    }
                }
                if(y1==y2){
                    for(auto x:pos[i]){
                        if(x.y!=y1){
                            flag=1;
                            break;
                        }
                    }
                }
                ans.push_back({x1,y1,pos[i][pos[i].size()-1].x,pos[i][pos[i].size()-1].y});
            }
        }
        if(flag){
            cout<<"NO"<<endl;
            continue;
        }
        for(i=0;i<mx;i++){
            for(j=ans[i].a;j<=ans[i].c;j++){
                for(k=ans[i].b;k<=ans[i].d;k++){
                    b[j][k]=i+1;
                }
            }
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(a[i][j]!=b[i][j]){
                    flag=1;
                    break;
                }
            }
            if(flag)
                break;
        }
        if(flag){
            cout<<"NO"<<endl;
        }
        else{
            cout<<"YES"<<endl;
            cout<<mx<<endl;
            for(i=0;i<mx;i++){
                cout<<ans[i].a<<" "<<ans[i].b<<" "<<ans[i].c<<" "<<ans[i].d<<endl;
            }
        }
    }
    return 0;
}
View Code

F题

一道状压,感觉比较好想,因为时限给了4s。

我们看到有9种,不难想到可以状压出状态,首先n和m的关系不能直接算,因为数据太大

因此需要一个媒介联通他们,这样这个不大于1024的数就起到了作用,我们发现如果可以枚举1024种情况,再分别维护n,m,复杂度在1e8左右

因此想到,1024种情况,分别计算他能够符合多少人,然后我们枚举面包,因为只能取两个面包,所以需要维护选这个面包能到达的状态的花费最小值和id

这样我们就可以枚举1024种情况计算选两个面包的答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=1e6+10;
const int mod=1e9+7;
ll f[N];
ll d[N];
ll cost[N],st[N],id[N];
vector<int> res;
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    int i,j,k;
    cin>>n>>m;
    for(i=1;i<=n;i++){
        int x;
        cin>>x;
        for(j=1;j<=x;j++){
            int tmp;
            cin>>tmp;
            f[i]|=(1<<(tmp-1));
        }
    }
    int ans=0;
    int tot=0x3f3f3f3f;
    memset(cost,0x3f,sizeof cost);
    for(i=0;i<1<<10;i++){
        for(j=1;j<=n;j++){
            if((f[j]&i)==f[j]){
                d[i]++;
            }
        }
    }
    res.push_back(1);
    res.push_back(2);
    for(i=1;i<=m;i++){
        ll x,c;
        cin>>x>>c;
        int tmp=0;
        for(j=1;j<=c;j++){
            int y;
            cin>>y;
            tmp|=(1<<(y-1));
        }
        for(j=0;j<1<<10;j++){
            if(st[j]){
                if(ans<d[j|tmp]){
                    ans=d[j|tmp];
                    tot=cost[j]+x;
                    res.clear();
                    res.push_back(id[j]);
                    res.push_back(i);
                }
                else if(ans==d[j|tmp]&&tot>cost[j]+x){
                    tot=cost[j]+x;
                    res.clear();
                    res.push_back(id[j]);
                    res.push_back(i);
                }
            }
        }
        st[tmp]=1;
        if(cost[tmp]>x){
            cost[tmp]=x;
            id[tmp]=i;
        }
    }
    cout<<res[0]<<" "<<res[1]<<endl;
    return 0;
}
View Code

G1题

状压dp,根据题目范围,设计状态为选择i,最后的种类是j,这样往大了更新即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
const int mod=1e9+7;
int a[N],b[N];
ll f[N][4];
int main(){
    ios::sync_with_stdio(false);
    int n,T;
    cin>>n>>T;
    int i,j,k;
    for(i=1;i<=n;i++){
        cin>>a[i]>>b[i];
    }
    f[0][0]=1;
    for(i=0;i<(1<<n);i++){
        for(j=0;j<=3;j++){
            for(k=1;k<=n;k++){
                if(i>>(k-1)&1)
                    continue;
                if(b[k]==j)
                    continue;
                f[i|(1<<k-1)][b[k]]=(f[i|(1<<k-1)][b[k]]+f[i][j])%mod;
            }
        }
    }
    ll ans=0;
    for(i=1;i<(1<<n);i++){
        int cnt=0;
        for(j=1;j<=n;j++){
            if(i>>(j-1)&1){
                cnt+=a[j];
            }
        }
        if(cnt==T){
            ans=(ans+f[i][1]+f[i][2]+f[i][3])%mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}
View Code

G2题

待补,没啥思路。

posted @ 2021-04-04 23:07  朝暮不思  阅读(61)  评论(0编辑  收藏  举报