23.8.7 牛客暑期多校7部分题解

G - Cyperation

题目大意

n n n 个数,定义 i ,   j ( i < j ) i,\space j(ii, j(i<j) 两个数的距离为 m i n ( j − i ,   n + i − j ) min(j-i,\space n+i-j) min(ji, n+ij),每次操作可以选择距离恰好为 k k k 的两个数减 1 1 1,问能否使此数列全部变为 0 0 0

解题思路

原来的数列全为 0 0 0 则不用操作,此外,如果 k > n 2 k>\frac{n}{2} k>2n 则无法操作

在剩余情况中,可以把每 k k k 个数取出来形成新环(可能不止一个环),在新环上就是相邻的数操作了

设新的数列为 { b i } \{b_i\} {bi},设 b 1 ,   b 2 b_1,\space b_2 b1, b2 减了 x 1 x_1 x1 b 2 ,   b 3 b_2,\space b_3 b2, b3 减了 x 2 x_2 x2 b m − 1 ,   b m b_{m-1},\space b_m bm1, bm 减了 x m − 1 x_{m-1} xm1 b m ,   b 1 b_m,\space b_1 bm, b1 减了 x m x_m xm

所以 b 1 = x m + x 1 ,   b 2 = x 1 + x 2 ,   b 3 = x 2 + x 3 b_1=x_m+x_1,\space b_2=x_1+x_2,\space b_3=x_2+x_3 b1=xm+x1, b2=x1+x2, b3=x2+x3 b m = x m − 1 + x m b_m=x_{m-1}+x_m bm=xm1+xm

这样就可以用 x 1 x_1 x1 b i b_i bi 表示所有 x i x_i xi,根据 x i ≥ 0 x_i\ge0 xi0 求出是否有 x 1 x_1 x1 满足条件即可

注意思考一些特殊条件即可

code

#include 
using namespace std;
const int N = 1e6 + 9;
int t, n, k, v[N], num, q[N], fl;
long long a[N], ma;
int main() {
    scanf("%d", &t);
    while (t --) {
        scanf("%d%d", &n, &k); ma = fl = 0;
        for (int i = 0; i < n; ++ i)
            scanf("%lld", &a[i]), ma = max(a[i], ma);
        if (ma == 0) {printf("YES\n"); continue;}
        if (k > n / 2) {printf("NO\n"); continue;}
        for (int i = 0; i < n; ++ i) v[i] = 0;
        for (int i = 0; i < n; ++ i) {
            if (v[i]) continue;
            num = 0; q[++ num] = i; v[i] = 1;
            for (int j = (i + k) % n; j != i; j = (j + k) % n)
                q[++ num] = j, v[j] = 1;
            long long cnt = 0, tmp = 1, l = 0, r = 1e9;
            for (int j = 2; j <= num; ++ j) {
                cnt = -cnt; tmp = -tmp; cnt += a[q[j]];
                if (tmp == 1) l = max(l, -cnt);
                else r = min(r, cnt);
            }
            if (tmp == 1) {
                if ((a[q[1]] - cnt) % 2 != 0) {fl = 1; break;}
                long long ans = (a[q[1]] - cnt) / 2;
                if (ans < l || ans > r || l > r) {fl = 1; break;}
            } else if (cnt != a[q[1]] || l > r) {fl = 1; break;}
        }
        if (fl) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

你可能感兴趣的:(数学,思维)