• [CodeForces]Codeforces Round #432 (Div. 2)


    A. Arpa and a research in Mexican wave

    题意

    分段函数求值。

    题解

    $egin{equation}
    f(t)=
    egin{cases}
    t&,0leq tleq k ewline
    k&,k< tleq n ewline
    n+k-t&,b< tleq n+k
    end{cases}
    end{equation}$

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        int n, k, t;
        cin >> n >> k >> t;
        if (t <= k) cout << t;
        else
            if (t <= n) cout << k;
            else cout << k - (t - n);
    }
    

    B. Arpa and an exam about geometry

    题意

    给定三个点$a,b,c$,判断能否通过旋转使得$a$和$b$重合,$b$和$c$重合。

    题解

    题述可行当且仅当$|ab|=|bc|$且$a,b,c$三点不共线。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    struct Point {
        double x, y;
    };
    inline double sqr(double x) {
        return x * x;
    }
    inline double dist(Point p, Point q) {
        return sqr(p.x - q.x) + sqr(p.y - q.y);
    }
    int main() {
        Point a, b, c;
        cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
        if ((a.x - b.x) * (b.y - c.y) == (a.y - b.y) * (b.x - c.x) || dist(a, b) != dist(b, c)) return 0 * puts("No");
        return 0 * puts("Yes");
    }
    

    C. Five Dimensional Points

    题意

    给定$N$个五维点$(a_i,b_i,c_i,d_i,e_i)$。求所有“坏点”,即存在其他两个点与它构成的向量张角为锐角的点。

    题解

    我们先考虑二维时,一个点若不是“坏点”,则周围最多$4$个点;三维时,是$6$个;以此类推,五维时,是$10$个。
    因此:当$N>11$时,全部都是“坏点”;$Nleq 11$时,$N^3$枚举一下即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1009;
    struct Point {
         int a, b, c, d, e;
     } p[N];
    int res[N];
    inline int read() {
        int s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    inline bool isBad(Point x, Point y) {
        return x.a * y.a + x.b * y.b + x.c * y.c + x.d * y.d + x.e * y.e > 0;
    }
    int main() {
        int n = read(), k = 0;
        for (int i = 1; i <= n; i++) p[i].a = read(), p[i].b = read(), p[i].c = read(), p[i].d = read(), p[i].e = read();
        if (n > 11) return 0 * puts("0");
        for (int i = 1; i <= n; i++) {
            bool flag = true;
            for (int j = 1; j < n; j++) if (i != j) {
                for (int k = j + 1; k <= n; k++) if (k != j && k != i) {
                    Point ab, ac;
                    ab.a = p[i].a - p[j].a; ab.b = p[i].b - p[j].b; ab.c = p[i].c - p[j].c; ab.d = p[i].d - p[j].d; ab.e = p[i].e - p[j].e;
                    ac.a = p[i].a - p[k].a; ac.b = p[i].b - p[k].b; ac.c = p[i].c - p[k].c; ac.d = p[i].d - p[k].d; ac.e = p[i].e - p[k].e;
                    if (isBad(ab, ac)) flag = false;
                    if (!flag) break;
                }
                if (!flag) break;
            }
            if (flag) res[k++] = i;
        }
        printf("%d
    ", k);
        for (int i = 0; i < k; i++) printf("%d ", res[i]);
        return 0;
    }
    

    D. Arpa and a list of numbers

    题意

    给定$n$个数$a_i$和两种操作:
    $1.$花费$x$将一个数删除;
    $2.$花费$y$将一个数加一。
    两种操作使用次数任意,求最小花费使得最后所有数的$gcd$不为$1$或全部删除。

    题解

    首先我们考虑枚举最后所有数的$gcd$,时间复杂度为$Theta(m)$,其中$m=max_{1leq ileq n}(a_i)$。
    然后考虑对于每个$gcd$计算对应花费,暴力枚举要再乘上$Theta(n)$肯定超时,而运用前缀和就可以做到整体复杂度为$Theta(mlnm)$(调和级数求和)。
    对于一个$gcd$,会将正整数划分成若干区间$[(k-1) imes gcd+1,k imes gcd]$。对于区间中的一个数$num$,使用操作$2$变成$k imes gcd$,需要的花费为$(k imes gcd-num) imes y$;使用操作$1$则需要花费为$x$。很显然,我们可以列出一个方程:$(k imes gcd-num) imes y=x$。解得:$num=k imes gcd-frac{y}{x}$。这个解(设$bound=k imes gcd-left lfloor frac{y}{x} ight floor$)如果在区间里的话,小于等于$bound$的数全部用操作$1$删去,大于$bound$的数全部用操作$2$变成$k imes gcd$;如果不在区间里的话,就全部删掉。
    也就是说每个区间被划分了至多两个连续区间,那么我们只要用前缀和预处理一下即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N = 5e5+9;
    const ll M = 1e6+9;
    ll a[N], p[M], cnt[2 * M], sum[2 * M];
    bool isPrime[M];
    inline ll read() {
        ll s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    inline void seizePrime() {
        for (ll i = 0; i < M; i++) isPrime[i] = 1;
        isPrime[0] = isPrime[1] = 0; p[0] = 0;
        for (ll i = 2; i < M; i++) {
            if (isPrime[i]) {
                p[ ++p[0] ] = i;
                for (ll j = 2 * i; j < M; j += i) isPrime[j] = 0;
            }
        }
    }
    int main() {
        ll n = read(), x = read(), y = read();
        for (ll i = 1; i <= n; i++) {
            a[i] = read();
            cnt[ a[i] ] ++;
            sum[ a[i] ] += a[i];
        }
        for (ll i = 1; i < 2 * M; i++) {
            cnt[i] += cnt[i - 1];
            sum[i] += sum[i - 1];
        }
        seizePrime();
        ll res = x * n;
        for (ll i = 1; i <= p[0]; i++) {
            ll g = p[i], tmp = 0;
            for (ll k = g; k < 2 * M; k += g) {
                if (k - x / y > k - g + 1) tmp += (cnt[k - x / y - 1] - cnt[k - g]) * x;
                ll b = max(k - x / y, k - g + 1);
                tmp += ((cnt[k - 1] - cnt[b - 1]) * k - (sum[k - 1] - sum[b - 1])) * y;
            }
            res = min(res, tmp);
        }
        return 0 * printf("%lld
    ", res);
    }
    

    E. Arpa and a game with Mojtaba

    题意

    给定$n$个数$a_i$,两个人轮流玩游戏,每人每轮操作任选一个素数$p$和一个正整数$k$,将$n$个数中可以整除$pk$的数除以$pk$。当且仅当一个人无法操作时,他就输了。判断谁有必胜策略。

    题解

    由于每个素数之间相互独立,我们对每个素数单独考虑,求出所有素数的$SG$值异或起来即可。
    下面,我们考虑如何对一个素数$p$求$SG$值。
    首先,用一个二进制数$mask$表示一个状态:第$i$位为$1$当且仅当该状态下存在数能够整除$pi$且不能$p{i+1}$整除。
    然后,当一个人选择了$k$时,就把$mask$大于等于$k$的位和原来的$mask$小于$k$的位进行或运算。即$mask$的下一个状态为$(mask>>k)cup (maskcap ((1<<k)-1))$。
    最后,我们在按上述方式构造出的图上$DFS$就能计算出每个素数的$SG$值。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 109;
    map<int, int> mask, sg;
    inline ll read() {
        ll s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    inline void calc(int a) {
        for (int p = 2; p * p <= a; p++) {
            int k = 0;
            while (a % p == 0) a /= p, k++;
            if (k > 0) mask[p] |= (1 << (k - 1));
        }
        if (a > 1) mask[a] |= 1;
    }
    inline int getSG(int msk) {
        if (sg.count(msk)) return sg[msk];
        int bit1 = 0, bit[32];
        memset(bit, 0, sizeof(bit));
        for (int k = 0; (1 << k) <= msk; k++) {
            bit[ getSG((msk & bit1) | (msk >> (k + 1)))] = 1;
            bit1 |= (1 << k);
        }
        int k = 0;
        while (bit[k]) k++;
        return sg[msk] = k;
    }
    int main() {
        int n = read();
        for (int i = 1; i <= n; i++) {
            int a = read(); calc(a);
        }
        ll res = 0;
        for (auto pir : mask) res ^= getSG(pir.second);
        return 0 * puts(res == 0 ? "Arpa" : "Mojtaba");
    }
    
  • 相关阅读:
    C# 學習使用StatusStrip
    初學C#打印
    C# 學習使用ErrorProvider
    C# 字符串中增、刪、替換字符學習
    mos开发系列教程八:页面代码研究地图控件页面结构
    MapGuide open source开发系列教程五: 屏幕坐标与地图坐标(问题)已修改
    ajax学习笔记一:动态更改div位置
    mos开发系列教七:框架分析
    mos开发系列教程十:说明
    MapGuide open source开发系列教程六: 地图状态与事件(含问题)
  • 原文地址:https://www.cnblogs.com/jstztzy/p/7485585.html
Copyright © 2020-2023  润新知