20182019 ACMICPC Brazil Subregional Programming Contest

2018-2019 ACM-ICPC Brazil Subregional Programming Contest

C. Pizza Cutter

  • 题意:一个矩形,给你一些横向纵向的边,问你能把矩形划分成多少区域?

  • 题解:打表找规律,答案为点数加边数+1,横纵交点能直接得到,同向交点即为两个方向的逆序对数量

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int x,y;
    int h,v;
    ll c[N];
    PII a[N],b[N];
    vector<int> alla,allb;
    ll ans;
     
    int get_alla(int x){
        return lower_bound(alla.begin(),alla.end(),x)-alla.begin()+1;
    }
     
    int get_allb(int x){
        return lower_bound(allb.begin(),allb.end(),x)-allb.begin()+1;
    }
     
    ll lowbit(ll x){
        return x&(-x);
    }
     
    void update(int n,int i,int k){
        while(i<=n){
            c[i]+=k;
            i+=lowbit(i);
        }
    }
     
    ll query(int i){
        ll res=0;
        while(i){
            res+=c[i];
            i-=lowbit(i);
        }
        return res;
    }
     
     
    int main() {
        scanf("%d %d",&x,&y);
     
        scanf("%d %d",&h,&v);
     
        for(int i=1;i<=h;++i){
            scanf("%d %d",&a[i].fi,&a[i].se);
            alla.pb(a[i].se);
        }
        for(int i=1;i<=v;++i){
            scanf("%d %d",&b[i].fi,&b[i].se);
            allb.pb(b[i].se);
        }
        sort(a+1,a+1+h);
        sort(b+1,b+1+v);
        sort(alla.begin(),alla.end());
        sort(allb.begin(),allb.end());
        alla.erase(unique(alla.begin(),alla.end()),alla.end());
        allb.erase(unique(allb.begin(),allb.end()),allb.end());
        ans+=h+v+1ll*h*v;
        for(int i=1;i<=h;++i){
            int cur=get_alla(a[i].se);
            ans+=i-1-query(cur);
            update((int)alla.size(),cur,1);
        }
        me(c,0,sizeof(c));
        for(int i=1;i<=v;++i){
            int cur=get_allb(b[i].se);
            ans+=i-1-query(cur);
            update((int)allb.size(),cur,1);
        }
        printf("%lld\n",ans+1);
        return 0;
    }
    

D. Unraveling Monty Hall

签到

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
 
int n;
int x;
 
int main() {
    scanf("%d",&n);
    int ans=0;
    for(int i=1;i<=n;++i){
        scanf("%d",&x);
        if(x!=1) ans++;
    }
    printf("%d\n",ans);
    return 0;
}

E. Enigma

签到

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
 
char t[N],s[N];
 
int main() {
    scanf("%s",t+1);
    scanf("%s",s);
    int n=strlen(t+1),m=strlen(s);
    int ans=0;
    for(int i=1;i+m-1<=n;++i){
        bool flag=true;
        for(int j=0;j<m;++j){
            if(t[i+j]==s[j]){
                flag=false;
                break;
            }
        }
        if(flag) ans++;
    }
    printf("%d\n",ans);
    return 0;
}

F. Music Festival

  • 题意:有\(n\)个舞台,每个舞台都有不同的时间端进行表演,每个表演都有权值,你每个舞台都至少要观看一场演出,每个演出的时间段都不能相交,问你观看演出的最大权值为多少,如果不能每个舞台都观看则输出-1

  • 题解\(n\)最大只有\(10\),考虑状压dp,暴力枚举时间,\(dp[i][j]\)表示当前时间为\(i\),状态为\(j\)的最大权值,再枚举以当前时间为起点的演出,则:\(dp[r][j]=max(dp[r][j],dp[i][k]+w)\),\(r\)表示结束时间,\(j\)表示转移到的状态,\(k\)表示转移前的状态。

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n;
    struct Node{
        int r;
        int w;
        int id;
    }e;
    vector<Node> v[N];
    int dp[90000][1200];
     
    int main() {
        scanf("%d",&n);
        me(dp,-1,sizeof(dp));
        for(int i=1;i<=n;++i){
            int m;
            scanf("%d",&m);
            for(int j=1;j<=m;++j){
                int l,r,w;
                scanf("%d %d %d",&l,&r,&w);
                v[l].pb({r,w,i});
            }
        }
        
        for(int i=1;i<=86400;++i){
           dp[i][0]=0;
           for(int j=1;j<(1<<n);++j){
               dp[i][j]=max(dp[i][j],dp[i-1][j]);
           }
           for(int j=0;j<(int)v[i].size();++j){
               for(int k=0;k<(1<<n);++k){
                    if(dp[i][k]==-1) continue;
                    int now=k|(1<<(v[i][j].id-1));
                    dp[v[i][j].r][now]=max(dp[v[i][j].r][now],dp[i][k]+v[i][j].w);
               }
           } 
        }
        printf("%d\n",dp[86400][(1<<n)-1]);
        return 0;
    }
    

I. Switches

不难发现\(2n\)次后就复原了,所以枚举两次\(n\)模拟就好了。

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
 
int n,m;
vector<int> v[N];
unordered_map<int,int> mp;
 
int main() {
    scanf("%d %d",&n,&m);
    int l;
    scanf("%d",&l);
    for(int i=1;i<=l;++i){
        int x;
        scanf("%d",&x);
        mp[x]=1;
    }
    for(int i=1;i<=n;++i){
        int k;
        scanf("%d",&k);
        for(int j=1;j<=k;++j){
            int x;
            scanf("%d",&x);
            v[i].pb(x);
        }
    }
    for(int i=1;i<=n;++i){
        for(auto w:v[i]){
            mp[w]=1-mp[w];
        }
        bool flag=true;
        for(int j=1;j<=m;++j){
            if(mp[j]==1){
                flag=false;
                break;
            }
        }
        if(flag){
            printf("%d\n",i);
            return 0;
        }
    }
    for(int i=1;i<=n;++i){
        for(auto w:v[i]){
            mp[w]=1-mp[w];
        }
        bool flag=true;
        for(int j=1;j<=m;++j){
            if(mp[j]==1){
                flag=false;
                break;
            }
        }
        if(flag){
            printf("%d\n",n+i);
            return 0;
        }
    }	
    puts("-1");
    return 0;
}

L. Subway Lines

  • 题意:一颗\(n\)个结点的树,\(q\)个询问,每次给你\(4\)个点,代表两条路径,问你两条路径的交点数

  • 题解:树上边的问题,不难想到树链剖分,分别对两条路径更新,在线段树将路径上的点+1,然后再查询任意一条路径,路径上权值为2的点即为两条路径相交的点

  • 代码

    #include <bits/stdc++.h>
     
    using namespace std;
    const int N=1e6+10;
    #define ll long long
    #define pb push_back
    int n,q;
    int dep[N],f[N],son[N],sz[N],wt[N],top[N],id[N],cnt;
    vector<int> edge[N];
     
    struct Node{
        int l,r;
        int cnt,tag,sum;
        int f;
    }tr[N<<4];
     
    void push_up(int u){
        tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
    }
     
    void push_down(int u){
        if(tr[u].f){
            tr[u<<1].cnt=tr[u<<1].tag=tr[u<<1].sum=0;
            tr[u<<1|1].cnt=tr[u<<1|1].tag=tr[u<<1|1].sum=0;
            tr[u<<1].f=tr[u<<1|1].f=1;
            tr[u].f=0;
        }
        if(tr[u].tag){
            tr[u<<1].cnt+=tr[u].tag;
            if(tr[u<<1].cnt==2) tr[u<<1].sum=tr[u<<1].r-tr[u<<1].l+1;
            tr[u<<1].tag+=tr[u].tag;
     
            tr[u<<1|1].cnt+=tr[u].tag;
            if(tr[u<<1|1].cnt==2) tr[u<<1|1].sum=tr[u<<1|1].r-tr[u<<1|1].l+1;
            tr[u<<1|1].tag+=tr[u].tag;
     
            tr[u].tag=0;
        }
    }
     
    void build(int u,int l,int r){
        if(l==r){
            tr[u]={l,r,0,0,0,0};
            return;
        }
        tr[u]={l,r,0,0,0,0};
        int mid=(l+r)>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        push_up(u);
    }
     
    void update(int u,int L,int R,int f){
        if(tr[u].l>=L && tr[u].r<=R){
            if(f){
                tr[u].cnt=tr[u].sum=0;
                tr[u].f=1;
                return;
            }
            tr[u].cnt++;
            tr[u].tag++;
            if(tr[u].cnt==2) tr[u].sum=(tr[u].r-tr[u].l+1);
            return;
        }
        push_down(u);
        int mid=(tr[u].l+tr[u].r)>>1;
        if(L<=mid) update(u<<1,L,R,f);
        if(R>mid) update(u<<1|1,L,R,f);
        push_up(u);
    }
     
    int query(int u,int L,int R){
        if(tr[u].l>=L && tr[u].r<=R) return tr[u].sum;
        push_down(u);
        int mid=(tr[u].l+tr[u].r)>>1;
        int res=0;
        if(L<=mid) res+=query(u<<1,L,R);
        if(R>mid) res+=query(u<<1|1,L,R);
        return res;
    }
     
    void dfs1(int u,int fa,int deep){
        dep[u]=deep;
        f[u]=fa;
        sz[u]=1;
        int mxson=-1;
        for(auto to:edge[u]){
            if(to==fa) continue;
            dfs1(to,u,deep+1);
            sz[u]+=sz[to];
            if(sz[to]>mxson) son[u]=to,mxson=sz[to];
        }
    }
     
    void dfs2(int u,int topf){
        id[u]=++cnt;
        wt[cnt]=1;
        top[u]=topf;
        if(!son[u]) return;
        dfs2(son[u],topf);
        for(auto to:edge[u]){
            if(to==f[u] || to==son[u]) continue;
            dfs2(to,to);
        }
    }
     
    void updrange(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            update(1,id[top[x]],id[x],0);
            x=f[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        update(1,id[x],id[y],0);
    }
     
    int queryrange(int x,int y){
        int ans=0;
        int res=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            res=query(1,id[top[x]],id[x]);
            ans+=res;
            x=f[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        res=query(1,id[x],id[y]);
        ans+=res;
        return ans;
    }
     
    int main(){
        scanf("%d %d",&n,&q);
     
        for(int i=1;i<n;++i){
            int u,v;
            scanf("%d %d",&u,&v);
            edge[u].pb(v);
            edge[v].pb(u);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        while(q--){
            int a,b,c,d;
            scanf("%d %d %d %d",&a,&b,&c,&d);
            updrange(a,b);
            updrange(c,d);
            printf("%d\n",queryrange(a,b));
            update(1,1,n,1);
        }
        return 0;
    }
    
原文地址:https://www.cnblogs.com/lr599909928/p/15587388.html