• 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)

  • 相关阅读:
    多表代换密码
    仿射变换
    LeetCode实战练习题目
    13.线性同余方程 扩展欧几里得算法
    12.扩展欧几里得算法
    11.快速幂求逆元
    10.快速幂
    9.筛法求欧拉函数
    8.欧拉函数
    7.最大公约数 欧几里得算法,也叫辗转相除法
  • 原文地址:https://www.cnblogs.com/kikokiko/p/12228374.html
Copyright © 2020-2023  润新知