zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC Northern Eurasia (Northeastern European Regional) Contest (NEERC 17) 日常训练

    A - Archery Tournament

    题目大意:按时间顺序出现靶子和射击一个位置,靶子的圆心为(x, y)半径为r,即圆与x轴相切,靶子不会重叠,靶子被击中后消失,

    每次射击找出哪个靶子被射中,或者没有射中靶子。

    思路:关键点在于,圆都与x轴相切,那么我们能发现,如果射击在(x, y) 这个点,包含它的圆只可能是它左边第一个直径>= y的圆c1,

    或者是它右边第一个直径 >=y 的圆c2,因为在c1 和 c2之间的圆不可能覆盖到(x, y), 因为它们的直径小于y,在c1左边和c2右边的圆

    通过画图我们也能得出不肯能包含(x, y),那么每次射击我们只需要check两个圆就好了。

    找圆的过程能用线段树维护,加入一个圆就在线段树对应的x的位置的值变成2*r,然后通过二分用线段树找圆,最后判一下是否在圆内。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define pii pair<int, int>
    
    using namespace std;
    
    const int N = 2e5 + 7;
    const int M = 1e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 +7;
    
    
    int n, tot, mx[N << 2], X[N], hs[N];
    
    struct Qus {
        int op, x, y;
    } qus[N];
    
    void update(int pos, int v, int l, int r, int rt) {
        if(l == r) {
            mx[rt] = v;
            return;
        }
    
        int mid = l + r >> 1;
        if(pos <= mid) update(pos, v, l, mid, rt << 1);
        else update(pos, v, mid + 1, r, rt << 1 | 1);
    
        mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
    }
    
    int getMx(int L, int R, int l, int r, int rt) {
        if(l >= L && r <= R) return mx[rt];
    
        int mid = l + r >> 1, ans = 0;
    
        if(L <= mid) ans = max(ans, getMx(L, R, l, mid, rt << 1));
        if(R > mid) ans = max(ans, getMx(L, R, mid + 1, r, rt << 1 | 1));
        return ans;
    }
    
    bool check(int x, int y, int id) {
        LL dis1 = 1ll * qus[id].y * qus[id].y;
        LL dis2 = 1ll * (x - qus[id].x) * (x - qus[id].x) + 1ll * (y - qus[id].y) * (y - qus[id].y);
        return dis1 > dis2;
    }
    
    int main() {
    
        scanf("%d", &n);
    
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d", &qus[i].op, &qus[i].x, &qus[i].y);
            hs[++tot] = qus[i].x;
        }
    
        sort(hs + 1, hs + 1 + tot);
        tot = unique(hs + 1, hs + 1 + tot) - hs - 1;
    
    
        for(int i = 1; i <= n; i++) {
            int op = qus[i].op, x = qus[i].x, y = qus[i].y;
    
            int pos = lower_bound(hs + 1, hs + 1 + tot, x) - hs;
    
            if(op == 1) {
                X[pos] = i;
                update(pos, 2 * y, 1, tot, 1);
            } else {
                int l = 1, r = pos, ret = -1;
                while(l <= r) {
                    int mid = l + r >> 1;
                    if(getMx(mid, pos, 1, tot, 1) >= y) ret = mid, l = mid + 1;
                    else r = mid - 1;
                }
    
                if(ret != -1 && check(x, y, X[ret])) {
                    printf("%d
    ", X[ret]);
                    update(ret, 0, 1, tot, 1);
                    continue;
                }
    
                l = pos, r = tot, ret = -1;
                while(l <= r) {
                    int mid = l + r >> 1;
                    if(getMx(pos, mid, 1, tot, 1) >= y) ret = mid, r = mid - 1;
                    else l = mid + 1;
                }
    
                if(ret != -1 && check(x, y, X[ret])) {
                    printf("%d
    ", X[ret]);
                    update(ret, 0, 1, tot, 1);
                    continue;
                }
    
                puts("-1");
    
            }
        }
        return 0;
    }
    View Code

    B - Box

    题目大意:问长宽高为a, b, c的立方体,能不能用n * m的纸折出来。

    思路:暴力枚举判断。。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define pii pair<int, int>
    
    using namespace std;
    
    const int N = 1000 + 7;
    const int M = 1e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 +7;
    
    
    int n, m, a[3], id[3];
    
    bool check(int x, int y) {
        if(x <= n && y <= m) return true;
        if(x <= m && y <= n) return true;
        return false;
    }
    int main() {
        scanf("%d%d%d", &a[0], &a[1], &a[2]);
        id[0] = 0, id[1] = 1, id[2] = 2;
        scanf("%d%d", &n, &m);
    
        sort(a, a + 3);
    
        do {
            int x = a[id[0]], y = a[id[1]], z = a[id[2]];
    
            if(check(2 * z + x, 2 * y + 2 * z)) {
                puts("Yes");
                return 0;
            }
    
            if(check(x + y + z, 2 * x + y + z)) {
                puts("Yes");
                return 0;
            }
    
            if(check(2 * z + x, x + 2 * y + z)) {
                puts("Yes");
                return 0;
            }
    
            if(check(3 * y + x + z, x + z)) {
                puts("Yes");
                return 0;
            }
        } while(next_permutation(id, id + 3));
        puts("No");
        return 0;
    }
    
    
    /*
    2z + x
    2y + 2z
    
    x + y + z
    2x + y + z
    
    2z + x
    x + 2y + z
    
    
    */
    View Code

    C - Connections

    题目大意:给你一个 n 个点 m (m >= 2 * n)条边的有向图,且原图为一个强连通分量,要求你选出2 * n条边,其他的删掉仍然是一个

    强连通分量。

    思路:比赛的时候我没想到,队友想出来的。。 用1号点跑一遍图,建反边用1号点再跑一次就好了。 应该挺听容易想到的,题目说2 * n

    应该想到由两个树组成。

    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    //#pragma GCC optimize("unroll-loops")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define ld long double
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    
    using namespace std;
    
    const double eps=1e-6;
    const int N=100000+10,maxn=500000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
    
    vector<pair<int,int> >v[N],rev[N];
    pii p[N];
    bool vis[N],used[N];
    void dfs(int u)
    {
        vis[u]=1;
        for(int i=0;i<v[u].size();i++)
        {
            int x=v[u][i].fi;
            if(!vis[x])
            {
                used[v[u][i].se]=1;
                dfs(x);
            }
        }
    }
    void dfs1(int u)
    {
        vis[u]=1;
        for(int i=0;i<rev[u].size();i++)
        {
            int x=rev[u][i].fi;
            if(!vis[x])
            {
                used[rev[u][i].se]=1;
                dfs1(x);
            }
        }
    }
    int main()
    {
        int T;scanf("%d",&T);
        while(T--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)v[i].clear(),rev[i].clear();
            for(int i=0;i<m;i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                v[x].pb(mp(y,i));
                rev[y].pb(mp(x,i));
                p[i]=mp(x,y);
                used[i]=0;
            }
            memset(vis,0,sizeof vis);
            dfs(1);
            memset(vis,0,sizeof vis);
            dfs1(1);
            int sum=0;
            for(int i=0;i<m;i++)
                if(used[i])
                    sum++;
            int now=2*n-sum;
            for(int i=0;i<m;i++)
            {
                if(!used[i]&&now)
                {
                    now--;
                    used[i]=1;
                }
            }
            for(int i=0;i<m;i++)
                if(!used[i])
                    printf("%d %d
    ",p[i].fi,p[i].se);
        }
        return 0;
    }
    /********************
    
    ********************/
    View Code

    D - Designing the Toy

    题目大意:给你三视图的每个面能看见的方块个数a, b, c,然后构造出这样的图形。

    思路:一起想了挺久的,三维立体很难实现,我们就考虑把所有点放一个面里面,构成图形的个数就是max(a, b, c),

    斜着放三面个数都加一,横着放两面个数加一,填补空缺一个面加一,构造一下。细节挺多的。。。

    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    //#pragma GCC optimize("unroll-loops")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define ld long double
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    
    using namespace std;
    
    const double eps=1e-6;
    const int N=100+10,maxn=500000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
    
    int a[3], b[3];
    
    struct point{
        int x,y,z;
    };
    int ok[N][N];
    void solve(int x,int y,int z){
        vector<point> v;
        vector<point> ans;
        for(int i=0;i<x;i++)
            v.pb({0,i,i});
        for(int i=x;i<y;i++)
            v.pb({0,x-1,i});
        for(int i=0;i<v.size();i++)ok[v[i].y][v[i].z]=1;
        int now=z-y;
        for(int i=0;i<x;i++)
        {
            for(int j=0;j<y;j++)
            {
                if(!ok[i][j]&&now)
                {
                    v.pb({0,i,j});
                    ok[i][j]=1;
                    now--;
                }
            }
        }
        if(now!=0){puts("-1");return ;}
        if(b[0]==a[0]&&b[1]==a[2]&&b[2]==a[1])
        {
            for(int i=0;i<v.size();i++)swap(v[i].x,v[i].y);
        }
        else if(b[0]==a[1]&&b[1]==a[0]&&b[2]==a[2])
        {
            for(int i=0;i<v.size();i++)swap(v[i].y,v[i].z);
        }
        else if(b[0]==a[1]&&b[1]==a[2]&&b[2]==a[0])
        {
            for(int i=0;i<v.size();i++)
            {
                swap(v[i].x,v[i].z);
                swap(v[i].y,v[i].z);
            }
        }
        else if(b[0]==a[2]&&b[1]==a[0]&&b[2]==a[1])
        {
            for(int i=0;i<v.size();i++)
            {
                swap(v[i].x,v[i].y);
                swap(v[i].y,v[i].z);
            }
        }
        else if(b[0]==a[2]&&b[1]==a[1]&&b[2]==a[0])
        {
            for(int i=0;i<v.size();i++)
            {
                swap(v[i].x,v[i].z);
            }
        }
        printf("%d
    ",v.size());
        for(int i=0;i<v.size();i++)
            printf("%d %d %d
    ",v[i].x,v[i].y,v[i].z);
    }
    int main(){
    
        for(int i = 0; i < 3; i++) {
            scanf("%d", &a[i]);
            b[i] = a[i];
        }
        sort(a, a + 3);
        solve(a[0],a[1],a[2]);
        return 0;
    }
    /********************
    
    ********************/
    View Code

    E - Easy Quest

    队友写的水题,不知道啥意思。

    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    //#pragma GCC optimize("unroll-loops")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define ld long double
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    
    using namespace std;
    
    const double eps=1e-6;
    const int N=20000+10,maxn=500000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
    
    multiset<int>p;
    int a[N];
    int ans[N];
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1,x;i<=n;i++)
        {
            scanf("%d",&x);
            if(x>0)a[x]++;
            else if(x==0)p.insert(i);
            else
            {
                if(a[-x]>0)a[-x]--;
                else if(p.size()!=0)
                {
    //                printf("--%d
    ",*p.begin());
                    ans[*p.begin()]=-x;
                    p.erase(p.begin());
                }
                else return 0*puts("No");
            }
        }
        while(p.size()!=0)ans[*p.begin()]=1,p.erase(p.begin());
        puts("Yes");
        for(int i=1;i<=n;i++)
            if(ans[i]!=0)
                printf("%d ",ans[i]);
        puts("");
        return 0;
    }
    /********************
    
    ********************/
    View Code

    补题****************************************************************************

    F - The Final Level

    题目大意,有若干个L形连通块,两边长为n,有一个重叠, 问你最少用几个能把(0 , 0)和(a, b)连起来, L形的物件不能有交叉。

    思路:分类讨论贪心,分为一下几种情况。

    1.a - x < n && b - y < n   用一个L就能连通

    2.a - x > n && b - y > n   贪心地继续连在前一个的末端

    3.a - x > n && b - y < n   y这维不用贪了,贪x这维。

    4.与3相反。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define pii pair<int, int>
    
    using namespace std;
    
    const int N = 2e5 + 7;
    const int M = 1e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 +7;
    
        
    int T;
    LL a, b, n;
    bool flag = false;
    vector<pair<pair<LL, LL>, pair<LL, LL> > > ans;
    
    void dfs(LL x, LL y) {
        if(a - x < n && b - y < n) {
            if(!flag) {
                int x1 = x - (x + n - 1 - a);
                int y1 = y;
                int x2 = a;
                int y2 = y + n - 1;
                ans.push_back(mk(mk(x2, y2), mk(x1, y1)));
                return;
            } else {
                int x2 = x;
                int y2 = y - (y + n - 1 - b);
                int x1 = x + n - 1;
                int y1 = b;
                ans.push_back(mk(mk(x2, y2), mk(x1, y1)));
            }
            return;
        }
    
        if(b - y < n) {
            ans.push_back(mk(mk(x + n - 1, y - n + 1), mk(x, y)));
            flag = true;
            dfs(x + n, y);
            return;
        }
    
        if(a - x < n) {
            ans.push_back(mk(mk(x, y), mk(x - n + 1, y + n - 1)));
            flag = false;
            dfs(x, y + n);
            return;
        }
    
    
        if(a - x >= n && b - y >= n) {
            ans.push_back(mk(mk(x + n - 1, y + n - 1), mk(x, y)));
            if(abs(a - x) >= abs(b - y)) flag = true, dfs(x + n, y + n - 1);
            else flag = false, dfs(x + n - 1, y + n);
            return;
        }
    
    }
    
    int main() {
        scanf("%d", &T);
        while(T--) {
            ans.clear();
            scanf("%lld%lld%lld", &a, &b, &n);
            int x = a, y = b;
            if(a < 0) a = -a;
            if(b < 0) b = -b;
    
            dfs(0, 0);
    
            for(int i = 0; i < ans.size(); i++) {
                if(a != x) ans[i].fi.fi = -ans[i].fi.fi, ans[i].se.fi = -ans[i].se.fi;
                if(b != y) ans[i].fi.se = -ans[i].fi.se, ans[i].se.se = -ans[i].se.se;
            }
    
            printf("%d
    ", (int) ans.size());
    
            for(int i = 0; i < ans.size(); i++) {
                printf("%lld %lld %lld %lld
    ", ans[i].fi.fi, ans[i].fi.se, ans[i].se.fi, ans[i].se.se);
            }
        }
        return 0;
    }
    
    
    /*
    1
    4 1 3
    */
    View Code
  • 相关阅读:
    第十二章学习笔记
    UVa OJ 107 The Cat in the Hat (戴帽子的猫)
    UVa OJ 123 Searching Quickly (快速查找)
    UVa OJ 119 Greedy Gift Givers (贪婪的送礼者)
    UVa OJ 113 Power of Cryptography (密文的乘方)
    UVa OJ 112 Tree Summing (树的求和)
    UVa OJ 641 Do the Untwist (解密工作)
    UVa OJ 105 The Skyline Problem (地平线问题)
    UVa OJ 100 The 3n + 1 problem (3n + 1问题)
    UVa OJ 121 Pipe Fitters (装管子)
  • 原文地址:https://www.cnblogs.com/CJLHY/p/9291194.html
Copyright © 2011-2022 走看看