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

A. Arpa and a research in Mexican wave

题意

分段函数求值。

题解

$\begin{equation}
f(t)=
\begin{cases}
t&,0\leq t\leq k\newline
k&,k< t\leq n\newline
n+k-t&,b< t\leq 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$时,全部都是“坏点”;$N\leq 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\n", 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_{1\leq i\leq n}(a_i)$。
然后考虑对于每个$gcd$计算对应花费,暴力枚举要再乘上$\Theta(n)$肯定超时,而运用前缀和就可以做到整体复杂度为$\Theta(mlnm)$(调和级数求和)。
对于一个$gcd$,会将正整数划分成若干区间$[(k-1)\times gcd+1,k\times gcd]$。对于区间中的一个数$num$,使用操作$2$变成$k\times gcd$,需要的花费为$(k\times gcd-num)\times y$;使用操作$1$则需要花费为$x$。很显然,我们可以列出一个方程:$(k\times gcd-num)\times y=x$。解得:$num=k\times gcd-\frac{y}{x}$。这个解(设$bound=k\times gcd-\left \lfloor \frac{y}{x}\right \rfloor$)如果在区间里的话,小于等于$bound$的数全部用操作$1$删去,大于$bound$的数全部用操作$2$变成$k\times 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\n", res);
}

E. Arpa and a game with Mojtaba

题意

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

题解

由于每个素数之间相互独立,我们对每个素数单独考虑,求出所有素数的$SG$值异或起来即可。
下面,我们考虑如何对一个素数$p$求$SG$值。
首先,用一个二进制数$mask$表示一个状态:第$i$位为$1$当且仅当该状态下存在数能够整除$pi$且不能$p$整除。
然后,当一个人选择了$k$时,就把$mask$大于等于$k$的位和原来的$mask$小于$k$的位进行或运算。即$mask$的下一个状态为$(mask>>k)\cup (mask\cap ((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");
}
posted @ 2017-09-06 16:35  jstztzy  阅读(166)  评论(0编辑  收藏  举报