Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)

A. Prison Break

很明显是n*m

B. Restore Modulo

乱搞搞过得去的,讨论了一下增情况和减情况这样。

wa了两发

#include<bits/stdc++.h>
#define inf 1e18
#define ll long long
#define MAX 1000001
const ll N = 1e5+7;
const ll mod = 1e18;
using namespace std;
ll a[N];
int main(){
    ll t;cin>>t;
    while(t--){
        ll n,m,maxx=-1,ff=0;cin>>n;
        ll d=0,z=0,flag=0;
        for(int i=1;i<=n;++i){
            cin>>a[i];
            maxx=max(a[i],maxx);
        }
        for(int i=2;i<=n;++i){
            ll x=a[i]-a[i-1];
            if(x>0){
                if(d==0)d=x;
                else if(x!=d)    ff=1;
            }
            else if(x<0){
                if(z==0)z=x;
                else if(x!=z)    ff=1;
            }
            else{
                flag=1;
            }
        }
        if(ff==1){
            printf("-1
");
            continue;
        }
        if(flag==1&&(d>0||z<0)){
            printf("-1
");
            continue;
        }
        if(d>0&&z<0){
            m=d-z;
            if(m<maxx){
                printf("-1
");
            }
            else{
                printf("%lld %lld
",m,d);
            }
        }
        else{
            printf("0
");
        }
    }
    return 0; 
}

C. Basic Diplomacy

题意:给定n个人和m天

每天会给一些人可以选

要求最多被选的人的次数不超过 向上取整m/2

有一些天只能选一个。

如果这些被迫选的人的其中某个已经过要求了,那直接出NO

如果这些被迫选的人已经占据了是k天。0≤k≤ (向上取整m/2)

剩下的m-k天还没选,每天都至少有两个人可以选。

极端化情况,k天都是A占据的,剩下两天都只有A和B。测试最困难的情况。

此时

A 占据 k天 0 ≤ k ≤ (m+1)/2  A/B 共同占据(m-k)天

先设A= (m+1)/2天,不关k的情况,k小就往共同里面填,A不够了填B= m-(m+1)/2  <  (m+1)/2

这样构造满足k的任意情况,证明结束。

如果可以的话,也可以试试网络流

#include<bits/stdc++.h>
#define inf 1e18
#define ll long long
#define MAX 1000001
const ll N = 1e5+7;
const ll mod = 1e18;
using namespace std;
int vis[N],vis2[N],n,m,maxx,ans[N];
vector<int>G[N];
int main(){
    ll t;cin>>t;
    while(t--){
        int flag=0;cin>>n>>m;
        for(int i=1;i<=n;++i)vis[i]=vis2[i]=0;
        for(int i=1;i<=m;++i)G[i].clear(),ans[i]=0;
        
        maxx=(m+1)/2;
        for(int i=1;i<=m;++i){
            int x;scanf("%d",&x);
            for(int j=1;j<=x;++j){
                int q;scanf("%d",&q);
                G[i].push_back(q);
            }
            if(x==1){
                vis[G[i][0]]++;
                if(vis[G[i][0]]>maxx)    flag=1;
                ans[i]=G[i][0];
                vis2[G[i][0]]++;
            }
        }
        
        if(flag==1)printf("NO
");
        else{
            for(int i=1;i<=m;++i){
                if(ans[i])    continue;            //避免vis2的重复计算 
                for(int j=0;j<G[i].size();++j){
                    if(vis2[G[i][j]]<maxx){
                        ans[i]=G[i][j];
                        vis2[G[i][j]]++;
                        break;
                    }
                }
            }
            
            printf("YES
");
            for(int i=1;i<=m;++i)
                printf("%d ",ans[i]);
            printf("
");
        }
    }
    return 0; 
}
//之前那样写会出现 前面有别的选择但是已经取了但是后面只能取然后超过的情况。 

D. Playlist

参考了某位大佬的代码

并查集维护循环删除过程中,每个人的下一个。

但是因为路径压缩优化的原因,我们只能存下一个的左边那一个。

然后队列维护删除的情况。

因为新的情况只会在改变之后出现在原来的位置上。

----

线段树+循环列表也能维护这个东西

#include<bits/stdc++.h>
#define inf 1e18
#define ll long long
#define MAX 1000001
const ll N = 1e5+7;
const ll mod = 1e18;
using namespace std;
int del[N],a[N],n,fa[N];
vector<int> ans;
int nxt(int x){
    return x%n+1;
}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main(){
    int t;cin>>t;
    while(t--){
        ans.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            fa[i]=i;del[i]=0; 
        }
        queue<int>qe;
        for(int i=1;i<=n;++i)
            if(__gcd(a[i],a[nxt(i)])==1)qe.push(i);
        while(!qe.empty()){
            int x=qe.front();
            qe.pop();
            if(del[x])    continue;
            int y=nxt(find(x));
            fa[x]=find(y);del[y]=1;
            ans.push_back(y);
            if(__gcd(a[x],a[nxt(fa[x])])==1)    qe.push(x);
        }
        printf("%d ",ans.size());
        for(int i=0;i<ans.size();++i)
            printf("%d ",ans[i]);
        puts("");
    }
    return 0;
} 

 E. Skyline Photo

推荐阅读

https://blog.csdn.net/Brian_Pan_/article/details/115065320

#include<bits/stdc++.h>
#define inf 1e18
#define ll long long
#define MAX 1000001
const ll N = 3e5+7;
const ll mod = 1e18;
using namespace std;
ll f[N],a[N],b[N],c[N],n;
struct node{
    ll l,r;
    ll maxn,addv;
}tr[N<<2];
void build(ll o,ll l,ll r){
    tr[o].l=l;tr[o].r=r;
    if(l==r){
        return ;
    }
    ll mid=l+r>>1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
}
void pushup(ll o){
    tr[o].maxn=max(tr[o<<1].maxn,tr[o<<1|1].maxn);
}
void pushdown(ll o){
    if(tr[o].addv==0)    return ;
    tr[o<<1].addv+=tr[o].addv;
    tr[o<<1].maxn+=tr[o].addv;
    tr[o<<1|1].addv+=tr[o].addv;
    tr[o<<1|1].maxn+=tr[o].addv;
    tr[o].addv=0;
}
void update_seg(ll o,ll a,ll b,ll k){
    if(a<=tr[o].l&&tr[o].r<=b){
        tr[o].addv=tr[o].addv+k;
        tr[o].maxn=tr[o].maxn+k;
        return ;
    }
    pushdown(o);
    ll mid=tr[o].r+tr[o].l>>1;
    if(a<=mid)    update_seg(o<<1,a,b,k);
    if(b>mid)    update_seg(o<<1|1,a,b,k);
    pushup(o);
}
void update_pos(ll o,ll pos, ll v){
    if(tr[o].l==tr[o].r){
        tr[o].maxn=v;
        return ;
    }
    ll mid=tr[o].r+tr[o].l>>1;
    if(pos<=mid)    update_pos(o<<1,pos,v);
    else        update_pos(o<<1|1,pos,v);
    pushup(o);
}
ll query(ll o,ll a,ll b){
    if(a<=tr[o].l&&tr[o].r<=b)
        return tr[o].maxn;
    pushdown(o);
    ll ans=-inf;
    ll mid=tr[o].l+tr[o].r>>1;
    if(a<=mid)    ans=query(o<<1,a,b);
    if(b>mid)    ans=max(ans,query(o<<1|1,a,b));
    return ans;
}
int main(){
    scanf("%lld",&n);
    build(1,0,n);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    for(int i=1;i<=n;++i)scanf("%lld",&b[i]);
    a[0]=-1;f[1]=0;
    int cnt=1;
    for(int i=1;i<=n;++i){
        while(a[c[cnt]]>=a[i] && cnt){
            update_seg(1,c[cnt-1],c[cnt]-1,-b[c[cnt]]);
            //c[cnt-1]到c[cnt]-1减去b[c[cnt]]
            --cnt;
        }
        update_seg(1,c[cnt],i-1,b[i]);
        //c[cnt]到i-1加上b[i]
        f[i]=query(1,0,i-1);
        update_pos(1,i,f[i]);
        //单点修改 maxx i为fi 
        c[++cnt]=i;
    }
    printf("%lld
",f[n]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/PdrEam/p/14572508.html