2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)

Posted kikokiko

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)相关的知识,希望对你有一定的参考价值。

[2018-2019 ACM-ICPC Brazil Subregional Programming Contest]

(A.Slackline Adventure)

(B.Marbles)

NIM游戏,把其中任意一个石子移动到(0,0)算赢,所以必败态为全部石子都到(1,2)和(2,1)这两个点而不是(0,0)了,跑出sg函数异或即可,注意如果出现先手直接赢的需要特判

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 111;
int n,sg[MAXN][MAXN];
bool vis[MAXN<<2];
void getsg(){
    for(int i = 1; i <= 100; i++) sg[i][0] = sg[0][i] = sg[i][i] = 0;
    for(int k = 1; k <= 200; k++){
        for(int i = max(0,k-100); i <= min(100,k); i++){
            memset(vis,0,sizeof(vis));
            int j = k - i;
            if(i==j) continue;
            for(int u = 1; u < i; u++) if(i-u!=j) vis[sg[i-u][j]] = true;
            for(int u = 1; u < j; u++) if(i!=j-u) vis[sg[i][j-u]] = true;
            for(int u = 1; u < min(i,j); u++) vis[sg[i-u][j-u]] = true;
            for(int u = 0; ; u++) if(!vis[u]){
                sg[i][j] = u;
                break;
            }
        }
    }
}
int main(){
    getsg();
    scanf("%d",&n);
    int res = 0;
    for(int i = 1; i <= n; i++){
        int x,y;
        scanf("%d %d",&x,&y);
        if(x==y) return puts("Y");
        res^=sg[x][y];
    }
    puts(res?"Y":"N");
    return 0;
}

(C.Pizza Cutter)

两维分开处理,离散化之后按第一维从小到大排序+树状数组统计,只要找到右端点比当前点右端点高的数量即可

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
const int MAXN = 2e5+7;
int n,m;
LL res;
pair<int,int> coor[MAXN];
vector<int> vec;
struct BinaryIndexedTree{
    int val[MAXN];
    #define lowbit(x) ((x)&-(x))
    void update(int pos){
        while(pos){
            val[pos]++;
            pos-=lowbit(pos);
        }
    }
    int query(int pos){
        int r = 0;
        while(pos<MAXN){
            r += val[pos];
            pos+=lowbit(pos);
        }
        return r;
    }
}BIT;
int main(){
    scanf("%d %d %d %d",&n,&m,&n,&m);
    for(int i = 1; i <= n; i++){
        scanf("%d %d",&coor[i].first,&coor[i].second);
        vec.emplace_back(coor[i].first);
        vec.emplace_back(coor[i].second);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    for(int i = 1; i <= n; i++){
        coor[i].first = lower_bound(vec.begin(),vec.end(),coor[i].first) - vec.begin() + 1;
        coor[i].second = lower_bound(vec.begin(),vec.end(),coor[i].second) - vec.begin() + 1;
    }
    sort(coor+1,coor+1+n);
    for(int i = 1; i <= n; i++){
        res += 1 + BIT.query(coor[i].second);
        BIT.update(coor[i].second);
    }
    vec.clear();
    memset(BIT.val,0,sizeof(BIT.val));
    for(int i = 1; i <= m; i++){
        scanf("%d %d",&coor[i].first,&coor[i].second);
        vec.emplace_back(coor[i].first);
        vec.emplace_back(coor[i].second);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    for(int i = 1; i <= m; i++){
        coor[i].first = lower_bound(vec.begin(),vec.end(),coor[i].first) - vec.begin() + 1;
        coor[i].second = lower_bound(vec.begin(),vec.end(),coor[i].second) - vec.begin() + 1;
    }
    sort(coor+1,coor+1+m);
    for(int i = 1; i <= m; i++){
        res += 1 + n + BIT.query(coor[i].second);
        BIT.update(coor[i].second);
    }
    printf("%I64d
",res+1);
    return 0;
}

(D.Unraveling Monty Hall)

温暖签到

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int main(){
    int n,ans=0,x;
    scanf("%d",&n);
    while(n--){
        scanf("%d",&x);
        ans += (x!=1?1:0);
    }
    printf("%d
",ans);
    return 0;
}

(E.Enigma)

温暖签到 1e8只要跑34ms?

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e4+7;
char s[MAXN],t[MAXN];
int main(){
    scanf("%s %s",s+1,t+1);
    int lens = strlen(s+1);
    int lent = strlen(t+1);
    int cnt = 0;
    for(int i = 1; i <= lens-lent+1; i++){
        bool ok = true;
        for(int j = i; j <= i + lent-1; j++){
            if(s[j]==t[j-i+1]){
                ok = false;
                break;
            }
        }
        cnt += ok ? 1: 0;
    }
    cout << cnt << endl;
    return 0;
}

(F.Music Festival)

发现N只有10,想到状态压缩,要求最后所有stage都去过并且最后听的歌最多,考虑(f[msk][i])表示当前去过的stage位(msk)中的(1),当前时间为(i),此时听的歌最多是多少,从前面最大的转移即可,找最大可以用线段树维护,可以先离散化处理

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2222;
int n;
vector<pair<pair<int,int>,pair<int,int>>> perf;
vector<int> vec;
struct SegmentTree{
    int maxx[MAXN<<2],l[MAXN<<2],r[MAXN<<2];
    #define ls(rt) (rt) << 1
    #define rs(rt) (rt) << 1 | 1
    #define pushup(rt) maxx[rt] = max(maxx[ls(rt)],maxx[rs(rt)]);
    void build(int L, int R, int rt){
        l[rt] = L, r[rt] = R;
        maxx[rt] = -1;
        if(L+1==R) return;
        int mid = (L+R) >> 1;
        build(L,mid,ls(rt));
        build(mid,R,rs(rt));
    }
    void update(int pos, int rt, int x){
        if(l[rt]+1==r[rt]){
            maxx[rt] = x;
            return;
        }
        int mid = (l[rt]+r[rt]) >> 1;
        if(pos<mid) update(pos,ls(rt),x);
        else update(pos,rs(rt),x);
        pushup(rt);
    }
    int query(int L, int R, int rt){
        if(l[rt]>=R || L>=r[rt]) return -1;
        if(L<=l[rt] && r[rt]<=R) return maxx[rt];
        return max(query(L,R,ls(rt)),query(L,R,rs(rt)));
    }
}ST[MAXN];
int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        int sz;
        scanf("%d",&sz);
        for(int j = 0; j < sz; j++){
            int l, r, o;
            scanf("%d %d %d",&l,&r,&o);
            perf.emplace_back(make_pair(make_pair(l,r),make_pair(o,i)));
            vec.emplace_back(l);
            vec.emplace_back(r);
        }
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    for(int i = 0; i < (int)perf.size(); i++){
        perf[i].first.first = lower_bound(vec.begin(),vec.end(),perf[i].first.first) - vec.begin() + 1;
        perf[i].first.second = lower_bound(vec.begin(),vec.end(),perf[i].first.second) - vec.begin() + 1;
    }
    sort(perf.begin(),perf.end(),[](const pair<pair<int,int>,pair<int,int>> &A,const pair<pair<int,int>,pair<int,int>> &B){
        return A.first.first < B.first.first;
    });
    for(int msk = 0; msk < (1<<n); msk++) ST[msk].build(0,MAXN,1);
    ST[0].update(0,1,0);
    for(auto p : perf){
        for(int msk = 0; msk < (1<<n); msk++){
            if(!(msk&(1<<p.second.second))) continue;
            int maxx = max(ST[msk].query(0,p.first.first+1,1),ST[msk^(1<<p.second.second)].query(0,p.first.first+1,1));
            if(maxx==-1) continue;
            if(ST[msk].query(0,p.first.second+1,1)>=maxx+p.second.first) continue;
            ST[msk].update(p.first.second,1,maxx+p.second.first);
        }
    }
    printf("%d
",ST[(1<<n)-1].query(0,MAXN,1));
    return 0;
}

(G.Gasoline)

显然二分答案之后网络流


//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2222;
const int INF = 0x3f3f3f3f;
#define S 0
#define T MAXN-1
struct EDGE{
    int to,cap,rev;
    EDGE(){}
    EDGE(int to, int cap, int rev){
        this->to = to;
        this->cap = cap;
        this->rev = rev;
    }
};
pair<pair<int,int>,int> edge[MAXN<<4];
int p,r,m,pn[MAXN],rn[MAXN],tot,rk[MAXN],iter[MAXN];
vector<EDGE> G[MAXN];
void ADDEDGE(int u, int v, int cap){
    G[u].emplace_back(EDGE(v,cap,(int)G[v].size()));
    G[v].emplace_back(EDGE(u,0,(int)G[u].size()-1));
}
bool BFS(){
    queue<int> que;
    que.push(S);
    memset(rk,0,sizeof(rk));
    memset(iter,0,sizeof(iter));
    rk[S] = 1;
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(auto e : G[u]){
            if(!e.cap||rk[e.to]) continue;
            rk[e.to] = rk[u] + 1;
            que.push(e.to);
        }
    }
    return rk[T]!=0;
}
int dfs(int u, int f){
    if(u==T) return f;
    for(int &i = iter[u]; i < (int)G[u].size(); i++){
        EDGE &e = G[u][i];
        if(!e.cap||rk[e.to]!=rk[u]+1) continue;
        int d = dfs(e.to,min(f,e.cap));
        if(d){
            e.cap -= d;
            G[e.to][e.rev].cap += d;
            return d;
        }
    }
    return 0;
}
int Dinic(){
    int flow = 0;
    while(BFS()){
        int d = dfs(S,INF);
        while(d){
            flow += d;
            d = dfs(S,INF);
        }
    }
    return flow;
}
bool check(int mid){
    for(int i = 0; i < MAXN; i++) G[i].clear();
    for(int i = 1; i <= m; i++){
        if(edge[i].second>mid) continue;
        ADDEDGE(edge[i].first.second,edge[i].first.first+r,INF);
    }
    for(int i = 1; i <= p; i++) ADDEDGE(i+r,T,pn[i]);
    for(int i = 1; i <= r; i++) ADDEDGE(S,i,rn[i]);
    return Dinic()==tot;
}
int work(){
    int L = 1, R = 1e6;
    while(L<=R){
        int mid = (L+R) >> 1;
        if(check(mid)) R = mid - 1;
        else L = mid + 1;
    }
    return L>1e6?-1:L;
}
int main(){
    scanf("%d %d %d",&p,&r,&m);
    for(int i = 1; i <= p; i++){
        scanf("%d",&pn[i]);
        tot += pn[i];
    }
    for(int i = 1; i <= r; i++) scanf("%d",&rn[i]);
    for(int i = 1; i <= m; i++) scanf("%d %d %d",&edge[i].first.first,&edge[i].first.second,&edge[i].second);
    printf("%d
",work());
    return 0;
}

(H.Police Hypothesis)

(I.Switches)

最多操作(2n)次,暴力判断

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
int n,m,tot,light[MAXN];
vector<int> vec[MAXN];
bool press(int p){
    for(int pos : vec[p]){
        if(light[pos]) tot--;
        else tot++;
        light[pos]^=1;
    }
    return !tot;
}
int main(){
    scanf("%d %d",&n,&m);
    int l;
    scanf("%d",&l);
    for(int i = 1; i <= l; i++){
        int x;
        scanf("%d",&x);
        light[x] = 1;
        tot++;
    }
    for(int i = 1; i <= n; i++){
        int sz;
        scanf("%d",&sz);
        vec[i].resize(sz);
        for(int j = 0; j < sz; j++) scanf("%d",&vec[i][j]);
    }
    for(int i = 1; i <= 2*n; i++){
        if(press((i-1)%n+1)){
            printf("%d
",i);
            return 0;
        }
    }
    puts("-1");
    return 0;
}

(J.Joining Capitals)

(以下的Terminal点就是题中的Capital)
要求构造一棵所有的Terminal点都是叶子节点的最小斯坦纳树
(f[i][msk])表示以(i)为根节点,当前包含(msk)(1)所表示的Terminal点的最短总长
和一般构造斯坦纳树不同的地方在于

  • Terminal点不能作为合并点
  • 不能用一个Terminal点扩展另一个Terminal点为根的状态
  • 如果一个状态的根为Terminal点并且已经有连边,则不能扩展
    注意特判(k=2)的情况,这个情况下直接连接两个Terminal点即可
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
const int INF = 0x3f3f3f3f;
int n,k,st[MAXN],limit;
bool vis[MAXN];
pair<double,double> coor[MAXN];
double f[MAXN][MAXN];
queue<int> que;
double dist(const pair<double,double> &A, const pair<double,double> &B){
    return sqrt((A.first-B.first)*(A.first-B.first)+(A.second-B.second)*(A.second-B.second));
}
void spfa(int msk){
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = 1; i <= n; i++){
            if((u<=k&&i<=k)||(u<=k&&(msk!=st[u]))) continue;
            double dis = dist(coor[i],coor[u]);
            if(f[u][msk]+dis<f[i][st[i]|msk]){
                f[i][st[i]|msk] = f[u][msk]+dis;
                if(!vis[i]&&(st[i]|msk)==msk){
                    que.push(i);
                    vis[i] = true;
                }
            }
        }
    }
}
int main(){
    scanf("%d %d",&n,&k);
    for(int i = 0; i < MAXN; i++) fill(f[i],f[i]+MAXN,INF);
    for(int i = 1; i <= n; i++){
        scanf("%lf %lf",&coor[i].first,&coor[i].second);
        if(i<=k){
            st[i] = (1<<(i-1));
            f[i][st[i]] = 0;
        }
    }
    if(k==2) return printf("%.5f
",dist(coor[1],coor[2])),0;
    limit = 1<<k;
    for(int msk = 1; msk < limit; msk++){
        for(int i = 1; i <= n; i++){
            if(i<=k){
                if(f[i][msk]<INF) que.push(i),vis[i] = true;
                continue;
            }
            for(int sub = (msk-1)&msk; sub; sub = (sub-1)&msk)
                if(f[i][sub]+f[i][msk^sub]<f[i][msk]) f[i][msk] = f[i][sub] + f[i][msk^sub];
            if(f[i][msk]<INF) que.push(i),vis[i] = true;
        }
        spfa(msk);
    }
    printf("%.5f
",f[1][limit-1]);
    return 0;
}

(K.Kepler)

由于(0,0)点必然在圆内,并且根据题意两个圆的关系只存在相交(两个不同点)和包含两个关系,又由于(x,y)比较小,(r)比较大,所以按(r)进行排序之后暴力即可,利用break跳出后续无用情况:(r_2-r_1>50sqrt2)

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 150007;
int n;
struct Orbit{
    double x,y,r;
    bool operator < (const Orbit &rhs) const{
        return r < rhs.r;
    }
}orbit[MAXN];
double dist(double x1, double y1, double x2, double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int check(int I, int J){
    return abs(orbit[I].r-orbit[J].r) < dist(orbit[I].x,orbit[I].y,orbit[J].x,orbit[J].y);
}
int main(){
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) scanf("%lf %lf %lf",&orbit[i].x,&orbit[i].y,&orbit[i].r);
    sort(orbit+1,orbit+1+n);
    int tot = 0;
    for(int i = 1; i <= n; i++){
        for(int j = i+1; j <= n; j++){
            if(orbit[j].r-orbit[i].r>50*sqrt(2)) break;
            tot += check(i,j)*2;
            if(tot>2*n){
                cout << "greater" << endl;
                return 0;
            }
        }
    }
    cout << tot << endl;
    return 0;
}

(L.Subway Lines)

树上链交,用LCA+倍增做就行

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
vector<int> G[MAXN];
int n,m,par[MAXN][20],depth[MAXN];
void dfs(int u, int f){
    depth[u] = depth[f] + 1;
    par[u][0] = f;
    for(int i = 1; par[u][i-1]; i++) par[u][i] = par[par[u][i-1]][i-1];
    for(int v : G[u]){
        if(v==f) continue;
        dfs(v,u);
    }
}
int LCA(int u, int v){
    if(depth[u]<depth[v]) swap(u,v);
    for(int i = 0; depth[u]-depth[v]; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
    if(u==v) return u;
    for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
        u = par[u][i];
        v = par[v][i];
    }
    return par[u][0];
}
int intersect(int u, int depu, int v, int depv){
    if(depu>depth[v]||depv>depth[v]) return 0;
    if(depth[u]<depth[v]){
        swap(u,v);
        swap(depu,depv);
    }
    for(int i = 0; depth[u]-depth[v]; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
    if(depth[u]<depu) return 0;
    if(u==v) return depth[u] - max(depu,depv) + 1;
    for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
        u = par[u][i];
        v = par[v][i];
    }
    return max(0,depth[u]-max(depu,depv));
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d %d",&u,&v);
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    dfs(1,0);
    for(int i = 1; i <= m; i++){
        int ua,va,ub,vb;
        scanf("%d %d %d %d",&ua,&va,&ub,&vb);
        int depa = depth[LCA(ua,va)], depb = depth[LCA(ub,vb)];
        printf("%d
",intersect(ua,depa,ub,depb)+intersect(ua,depa,vb,depb+1)+intersect(va,depa+1,ub,depb)+intersect(va,depa+1,vb,depb+1));
    }
    return 0;
}

(M.Modifying SAT)

以上是关于2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)的主要内容,如果未能解决你的问题,请参考以下文章

2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)

2018-2019 ACM-ICPC Brazil Subregional Programming Contest

gym101908 [2018-2019 ACM-ICPC Brazil Subregional Programming Contest] 题解

2018-2019 ACM-ICPC Brazil Subregional Programming Contest B. Marbles

2019-2020 ACM-ICPC Brazil Subregional Programming Contest (7/10)

2019-2020 ACM-ICPC Brazil Subregional Programming Contest Problem A Artwork (并查集)