Codeforces Round #532 (Div. 2) (A,B,C,D,E,F)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZscDst/article/details/88848746

A. Roman and Browser

n个数只有(1/-1),你可以选择一个位置b,然后把所有c位置的数删除, c=b+i*k ( i 可以为任意整数),求|cnt_{-1}-cnt_{1}|的最大值

思路

直接暴力枚举b然后搞一遍就OK

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, k, a[MAXN];
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    int ans = 0;
    for (int b = 1; b <= k; b++)
    {
        int x1 = 0, x2 = 0;
        for (int i = 1; i <= n; i++)
        {
            if ((i - b) % k == 0) continue;
            if (a[i] == 1) x1++;
            else x2++;
        }
        ans = max(ans, abs(x1 - x2));
    }
    printf("%d\n", ans);
    return 0;
}
/*
4 2
1 1 -1 1
*/

B. Build a Contest

n个数范围为1~k的数字,问到当前位置是否能够凑齐1~k(凑齐一套以后把每个数的个数减一),可以该位为1,否则为0。

思路

set存是否够k个,cnt数组维护每个数字的个数,扫一遍就OK。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, a[MAXN], cnt[MAXN];
set<int> s;
int main()
{
    scanf("%d%d", &m, &n);
    string ans;
    int t = 0;
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
        s.insert(a[i]);
        cnt[a[i]]++;
        if (s.size() == m)
        {
            for (int j = 1; j <= m; j++)
            {
                cnt[j]--;
                if (cnt[j] == 0) s.erase(j);
            }
            ans += '1';
        }
        else ans += '0';
    }
    cout << ans << endl;
    return 0;
}
/*
3 11
2 3 1 2 2 2 3 2 2 3 1
*/

C. NN and the Optical Illusion

一个如图片中的图形,给你内圆半径和外圆个数,求外圆半径

思路

设大圆半径为x可得\frac{x}{r+x}=sin(PI/n),解x即可。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const double PI = acos(-1);
int n, r;
int main()
{
    scanf("%d%d", &n, &r);
    double s = sin(PI / n);
    double x = s * r / (1 - s);
    printf("%.7f", x);
    return 0;
}
/*
3 1
*/

D. Dasha and Chess

交互题,999*999的网格,最多有667个黑车(走直线),你操控白王(可以攻击相邻的八个格子),让你在2000步攻击到一个黑子。

思路

花费500步把王移动到中间,然后以你画一个竖线和横线,四个区域散落着一些车,且一定有一个区域上的车小于167(667/4)个,我们朝着这个区域的反方向的对角线去走,一定可以。注意有些点有黑子不能去走。

#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
const int MAXN = 1e3 + 5;
int x, y, cnt[MAXN];
pair<int, int> a[MAXN];
bool vis[MAXN][MAXN];
void Move(int ex, int ey)
{
    while (x != ex || y != ey)
    {
        if (x < ex && vis[x + 1][y] == 0) x++;
        else if (x > ex && vis[x - 1][y] == 0) x--;
        if (y < ey && vis[x][y + 1] == 0) y++;
        else if (y > ey && vis[x][y - 1] == 0) y--;
        printf("%d %d\n", x, y);
        fflush(stdout);
        int k, xx, yy; scanf("%d%d%d", &k, &xx, &yy);
        if (k == -1) break;
        vis[a[k].X][a[k].Y] = 0;
        a[k] = make_pair(xx, yy);
        vis[a[k].X][a[k].Y] = 1;
    }
}
int main()
{
    scanf("%d%d", &x, &y);
    for (int i = 1; i <= 666; i++)
    {
        scanf("%d%d", &a[i].X, &a[i].Y);
        vis[a[i].X][a[i].Y] = 1;
    }
    Move(500, 500);
    for (int i = 1; i <= 999; i++)
    {
        for (int j = 1; j <= 999; j++)
        {
            if (!vis[i][j]) continue;
            if (i < x && j < y) cnt[0]++;
            if (i < x && j > y) cnt[1]++;
            if (i > x && j < y) cnt[2]++;
            if (i > x && j > y) cnt[3]++;
        }
    }
    if (cnt[0] <= 166) Move(999, 999);
    else if (cnt[1] <= 166) Move(999, 1);
    else if (cnt[2] <= 166) Move(1, 999);
    else Move(1, 1);
    return 0;
}

E. Andrew and Taxi

给定一个n个点m条边的有向图,现在需要通过反转一些边(花费为边权)的方向使得图中无环,最小化最大花费,输出这个花费和反转了哪些边

思路

最小化最大花费,显然想到二分。二分枚举这个值,然后拓扑排序判断边权比这个值大的边形成的图中是否存在环,如果还有环证明我们要增大这个值,否则减小这个值。

最后,比这个边小的那些边中哪些边需要反转呢,显然是u的拓扑序大于v的那些边。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
//
struct Edge
{
    int from, to, w;
    Edge() {}
    Edge(int from, int to, int w) : from(from), to(to), w(w) {}
};
struct Toposort
{
    int n, m, t, c[MAXN], topo[MAXN];
    vector<Edge> edges;
    vector<int> G[MAXN];
    int limit;

    void init(int n)
    {
        this->n = n, m = 0;
        edges.clear();
        for (int i = 0; i <= n; i++) G[i].clear();
    }

    void AddEdge(int from, int to, int w)
    {
        edges.push_back(Edge(from, to, w));
        m = edges.size();
        G[from].push_back(m - 1);
    }

    bool dfs(int u)
    {
        c[u] = -1;//访问标志
        for (auto& i : G[u])
        {
            Edge& e = edges[i];
            if (e.w <= limit) continue;
            if (c[e.to] < 0) return false;//存在有向环,失败退出
            else if (!c[e.to] && !dfs(e.to)) return false;
        }
        c[u] = 1; topo[t--] = u;
        return true;
    }

    bool toposort(int limit)
    {
        this->limit = limit;
        t = n;
        memset(c, 0, sizeof(c));
        for (int u = 1; u <= n; u++)
        {
            if (c[u]) continue;
            if (!dfs(u)) return false;
        }
        return true;
    }

}gao;

int n, m, pos[MAXN];
bool check(int x)
{
    return gao.toposort(x);
}
int main()
{
    scanf("%d%d", &n, &m);
    gao.init(n);
    while (m--)
    {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        gao.AddEdge(u, v, w);
    }
    int L = 0, R = (int)1e9 + 1;
    while (L < R)
    {
        int M = L + (R - L) / 2;
        if (check(M)) R = M;
        else L = M + 1;
    }
    check(L);
    for (int i = 1; i <= n; i++) pos[gao.topo[i]] = i;
    vector<int> ans;
    for (int i = 0; i < gao.edges.size(); i++)
    {
        auto& e = gao.edges[i];
        if (e.w <= L && pos[e.from] >= pos[e.to]) ans.push_back(i);
    }
    printf("%d %d\n", L, ans.size());
    for (auto& i: ans) printf("%d ", i + 1);
    return 0;
}
/*
5 6
2 1 1
5 2 6
2 3 2
3 4 3
4 5 5
1 5 4
*/

F. Ivan and Burgers

一个长度为n的数组c,Q次询问,每次询问[L,R]区间中xor和的最大值是多少?

思路

离线+线性基,以右端点为关键字排序,每次插入[1,R]区间的数,记录每个基最右面的位置,维护线性基。每个询问的最大值用大于L的基去构造即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 5e5 + 5;
struct LineBase
{
    LL a[61], b[61];
    int cnt;
    int idx[61];

    LineBase ()
    {
        cnt = 0;
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
    }

    bool insert (LL v, int pos)
    {
        for (int i = 60; i >= 0; i--)
        {
            if (v & (1LL<<i))
            {
                if (!a[i]) { a[i] = v; idx[i] = pos; break; }
                if (idx[i] < pos) swap(idx[i], pos), swap(a[i], v);
                v ^= a[i];
            }
        }
        return v > 0;
    }

    LL MAX(int l)
    {
        LL res = 0;
        for (int i = 60; i >= 0; i--)
            if ((res^a[i]) > res && idx[i] >= l) res ^= a[i];
        return res;
    }

    LL MIN()
    {
        for (int i = 60; i >= 0; i--)
            if (a[i]) return a[i];
        return 0;
    }

    void rbuild()
    {
        for (int i = 60; i >= 0; i--)
        {
            for (int j = i - 1; j >= 0; j--)
            {
                if (a[i] & (1LL<<j)) a[i] ^= a[j];
            }
        }
        for (int i = 0; i <= 60; i++)
            if (a[i]) b[cnt++] = a[i];
    }

    LL kth(LL k) // k小值
    {
        LL res = 0;
        if (k >= (1LL << cnt)) return -1;
        for (int i = 60; i >= 0; i--)
            if (k & (1LL << i)) res ^= b[i];
        return res;
    }


}LB;

struct Query
{
    int l, r, id;
    Query () {}
    Query (int l, int r, int id) : l(l), r(r), id(id) {} 
    bool operator < (const Query& rhs) const
    { 
        if (r != rhs.r) return r < rhs.r;
        return l < rhs.l;
    }
};
int n, q, c[MAXN];
LL ans[MAXN];
Query Q[MAXN];
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &c[i]);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) 
    {
        int l, r; scanf("%d%d", &l, &r);
        l--, r--;
        Q[i] = Query(l, r, i);
    }
    sort(Q, Q + q);
    int r = 0;
    for (int i = 0; i < q; i++)
    {
        while (r <= Q[i].r) LB.insert(c[r], r), r++;
        ans[Q[i].id] = LB.MAX(Q[i].l);
    }
    for (int i = 0; i < q; i++) printf("%lld\n", ans[i]);
    return 0;
}
/*
4
7 2 3 4
3
1 4
2 3
1 3
*/

猜你喜欢

转载自blog.csdn.net/ZscDst/article/details/88848746