• 【题录】CF#666 Div.2


    B.Power Sequence

    易知(c^{i})为递增序列,猜想当(a_{i}) 也为递增序列时总代价最小。

    证明:假设有 (i < j, a_{i}  leq a_{j});

    由 (|x| + |y| = max{|x + y|, |x - y|}) :

    (|a_{i} - c^{i}| + |a_{j} - c ^{j}| = max{|a_{i} + a_{j} - c_{i} - c_{j}|, |a_{i} - a_{j} - c^{i} + c^{j}| });

    (|a_{j} - c^{i}| + |a_{i} - c ^{j}| = max{|a_{i} + a_{j} - c_{i} - c_{j}|, |a_{j} - a_{i} - c^{i} + c^{j}| });

    由于(a_{j} - a_{i} geq 0, c^{j} - c^{i} > 0),所以 (|a_{i} - c^{i}| + |a_{j} - c ^{j}| leq |a_{j} - c^{i}| + |a_{i} - c ^{j}|)

    又由于c为指数级增长,所以暴力处理即可(n 小的时候 c 的可能性多,n 大的时候 c 的可能性小,依次枚举)

        #include <bits/stdc++.h>
        using namespace std;
        #define maxn 200000
        #define MAXC 1000000
        #define int unsigned long long
        #define INF 9123372036854775807LL
        int n, a[maxn], ans = INF;
         
        int read() {
            int x = 0, k = 1; char c = getchar();
            while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
            while(c >= '0' && c <= '9') { x = x * 10 + c - '0', c = getchar(); }
            return x * k;
        }
         
        int abs(int a, int b) {
            if(a < b) return b - a;
            else return a - b;
        }
         
        bool check(int c) {
            int tans = 0; bool ret = 1;
            for(int i = 0, t = 1; i < n; i ++, t *= c) {
                tans = tans + abs(a[i], t);
                if(a[i] < t && t - a[i] >= ans) {
                    ret = 0;
                    break;
                }
            }
            ans = min(ans, tans);
            return ret;
        }
         
        signed main() {
            n = read();
            for(int i = 0; i < n; i ++) a[i] = read();
            sort(a, a + n);
            for(int c = 1; c < MAXC; c ++)
                if(!check(c)) break;
            printf("%lld
    ", ans);
            return 0;
        }

    C.Multiples of Length

    试想:若对一个数可以进行两次操作,第一次加上 (p * a),第二次加上 (q * b), 其中(p, q) 为变量, (a, b) 为不相等的常数,则该数一定可以变为 (0)。

    由此,我们可以得出思路:

    1.若只有一个数字:修改一次后每次变化为(0)。

    2.若有一个以上的数字:可以第一步把第一个数字变为 (0)。第二步对剩下的 (n - 1) 个数字进行操作。第三步再对全体 (n) 个数字进行操作(第一个数字为 (0)不变,等价于 (a = n - 1, b = n))。联立方程对每一个 (a_{i}) 解出 (p, q) 输出。

        #include <bits/stdc++.h>
        using namespace std;
        #define maxn 400000
        #define int long long
        int n, a[maxn], rec[maxn];
         
        int read() {
            int x = 0, k = 1; char c = getchar();
            while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
            while(c >= '0' && c <= '9') { x = x * 10 + c - '0', c = getchar(); }
            return x * k;
        }
         
        signed main() {
            n = read();
            for(int i = 1; i <= n; i ++) a[i] = read();
            printf("1 1
    %lld
    ", -a[1]);
            if(n == 1) {
                printf("1 1
    0
    1 1
    0
    ");
                return 0;
            }
            printf("2 %lld
    ", n);
            for(int i = 2; i <= n; i ++) {
                int s = a[i] % n, t = (a[i] - s) / n;
                printf("%lld", s * (n - 1));
                if(i != n) printf(" "); else printf("
    ");
                rec[i] = t + s;
            }
            printf("1 %lld
    ", n);
            printf("0 ");
            for(int i = 2; i <= n; i ++) {
                printf("%lld", -rec[i] * n);
                if(i != n) printf(" "); else printf("
    "); 
            }
            return 0;
        }

    D.Stoned Game

    记石头的总数为 (S)。A.若存在一堆石头数目超过 (frac{S}{2}) ,则先手获胜(只需要一直拿这一堆即可)。

    B.若并非如此,则所有石头数目 (leq frac{S}{2})。

    若石头的总数为偶数:若先手走完后为情况 A,则接下来的先手获得胜利,即后手胜利。若先手走完后仍为情况B,则此时后手可以随意选择一堆石头拿走一个(由于B的前提条件此时必然还有可以拿的石堆)。分析在这两步之前:(a_{i} leq frac{S}{2}),走完之后 (S' = S - 2, frac{S'}{2} = frac{S}{2} - 1)。由于第一步走完之后进入B的条件与此相同,可知再拿走第二个石子满足:(a_{i} leq frac{S'}{2})。是以后手总有路可走,直到先手走完后为情况A胜利为止。

    若石头的总数为奇数:先手可以随便拿走一个,原先:(a_{i} leq frac{S - 1}{2}), 现(S' = S - 1),总数变为偶数且仍为B情况。所以此时后手即先手胜利。

        #include <bits/stdc++.h>
        using namespace std;
        #define maxn 100000
        int a[maxn];
         
        int read() {
            int x = 0, k = 1; char c = getchar();
            while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
            while(c >= '0' && c <= '9') { x = x * 10 + c - '0', c = getchar(); }
            return x * k;
        }
         
        int main() {    
            int T = read();
            while(T --) {
                int n = read(), S = 0; bool mark = 0;
                for(int i = 1; i <= n; i ++) a[i] = read(), S += a[i];
                for(int i = 1; i <= n; i ++) 
                    if(a[i] > (S >> 1)) { mark = 1; break; }
                if(mark || (!mark && (S & 1))) printf("T
    ");
                else printf("HL
    ");
            }
            return 0;
        }
  • 相关阅读:
    React Virtual Dom 与 Diff
    打造前端CI/CD工作流
    webpack-chain明细
    React项目中实现多语言支持
    【WPF】大量Canvas转换为本地图片遇到的问题
    【C#】【分享】 XX分钟学会C#
    【WPF】一些拖拽实现方法的总结(Window,UserControl)
    【WPF】 InkCanvas 书写毛笔效果
    js中this指向问题
    js原型浅谈理解
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/13610435.html
Copyright © 2020-2023  润新知