zoukankan      html  css  js  c++  java
  • ARC128 A-D简要题解

    ARC128 A-D简要题解

    A

    题意

    初始给定(1)个物品1,(0)个物品2 给定序列(A_i),每次可以把所有物品1变为(A_i)倍物品2,或者把所有物品2变为(frac{1}{A_i}) 倍物品1

    每次可以选择操作或者不操作,求最终的操作序列

    [2 leq N leq 2 imes10^5\ 1 leq A_i leq 10^9 ]

    分析

    显然我们有一个无脑的DP做法:

    (dp[i][0/1])表示前(i)次选择中进行了偶数/奇数次操作

    转移(dp[i][0] = max(dp[i -1][0],dp[i-1][1] / A[i]),dp[i][1] = max(dp[i-1][0] imes A[i],dp[i-1][1]))

    DP过程中记录转移路径,最后递归输出即可,这样做的问题是(A_i)值域过大,(dp)数组难以存储 处理方法可以用对所有数取log,当然这在有些情况可能出现精度问题

    事实上注意到(frac{a}{b} imes frac{b}{c} = frac{a}{c}) 所以直接贪心即可

    代码

    const int maxn = 2e5 + 5;
    double dp[maxn][2];
    double a[maxn];
    int path[maxn][2];
    int n;
    
    void dfs(int n,int op){
        if(!n) return;
        dfs(n - 1,path[n][op] ? op ^ 1 : op);
        printf("%d ",path[n][op]);
    }
    
    
    int main(){
        n = rd();
        for(int i = 1;i <= n;i++)
            a[i] = rd();
        dp[0][0] = log(1);
        dp[0][1] = -1e9;
        for(int i = 1;i <= n;i++){
            double x = dp[i - 1][0];
            double y = dp[i - 1][1] - log(a[i]);
            if(x > y) path[i][0] = 0;
            else path[i][0] = 1;
            dp[i][0] = max(x,y);
            double xx = dp[i - 1][0] + log(a[i]);
            double yy = dp[i - 1][1];
            if(xx > yy) path[i][1] = 1;
            else path[i][1] = 0;
            dp[i][1] = max(xx,yy);
        }
        dfs(n,0);
    }
    

    B.

    题意

    给定(R)个红球,(G)个绿球,(B)个蓝球

    可以做任意次以下操作:选择两个不同颜色的球把他们变为剩下颜色的球

    求最小的操作次数使得所有球变为同一个颜色

    [1 leq R,G,B leq 10^8 ]

    分析

    操作其实就是让两个数-1,另一个数+2

    手玩一下可以发现,通过3步操作,可以变为0,-3,+3

    这表示3步操作可以只改变其中两个数,改变的值是3,如果能够让三个数中某两个数相等,就可以不断对这两个操作达到结果

    因为只需要枚举不变的数,判剩下的数是否同余3即可

    代码

    int main(){
        int T = rd();
        while(T--){
            int a = rd();
            int b = rd();
            int c = rd();
            int ans = 1e9;
            if(abs(a - b) % 3 == 0) {
                int res = abs(a - b) / 3 * 3;
                res += min(a,b);
                ans = min(ans,res);
            }
            if(abs(a - c) % 3 == 0) {
                int res = abs(a - c) / 3 * 3;
                res += min(a,c);
                ans = min(ans,res);
            }
            if(abs(b - c) % 3 == 0) {
                int res = abs(b - c) / 3 * 3;
                res += min(b,c);
                ans = min(ans,res);
            }
            if(ans == 1e9) puts("-1");
            else cout << ans << '
    ';
        }
    }
    

    C

    题意

    给定数(M,S)

    给定长度(N)的数组(A)

    构造长度(N)的数组(X)满足

    [0 leq x_1 leq x_2...leq x_n leq M\ sum x_i = S ]

    [1 leq N leq 5000\ 1 leq M leq 10^6\ 1 leq S leq min(N imes M,10^6)\ 1 leq A_ileq 10^6 ]

    分析

    贪心性质还是比较明显吧

    (x)分配总是对一段后缀满足(x_i = x_{i + 1} = ...x{N})

    若存在(j <i)(x_j != 0) ,把这个(x_j)分配到(x_i)中最大的显然更优

    那么考虑后缀有数的情况就有两种:

    大小超过(M) ,这个时候说明有多余的(S),此时只需对前一段继续做一次贪心

    没有超过(M),全填(M)

    第一种情况的不超过(M)是可以钦定的,其实写起来还是有点烦琐

    代码

    const int maxn = 2e5 + 5;
    
    int main(){
        int n = rd();
        int m = rd();
        int s = rd();
        VI a(n);
        for(int i = 0;i < n;i++)
            a[i] = rd();
        VI x(n + 1),y(n + 1);
        ll sum = 0;
        for(int i = n - 1;i >= 0;i--){
            sum += a[i];
            x[n - i] = (ll)(n - i) * m;
            y[n - i] = (ll)sum * m;
        }
        double ans = 0;
        for(int i = 0;i  <= n;i++){
            if(x[i] <= s) 
                ans = max(ans,(double)y[i]);
        }
        for(int i = 0;i <= n;i++){
            if(x[i] < s) {
                for(int j = 0;j <= n;j++){
                    if(x[j] > s) {
                        ans = max(ans,((double)y[i] * (x[j] - s) + (double)y[j] * (s - x[i])) / (double)(x[j] - x[i]));
                    }
                }
            }
        }
        printf("%.10f",ans);
    }
    

    D

    题意

    给定(N)个数,若存在连续的(x,y,z)满足(A_x eq A_y ,A_y eq A_z) 就可以删除(A_y)

    可以执行无限次操作,求剩余序列的下标组成的序列个数

    [2 leq N leq 200000\ 1 leq A_i leq N ]

    分析

    显然如果存在(A_i = A_{i + 1})那么(i,i+1) 必定无法删除,换言之两边的方案独立

    于是问题变为了不存在(A_i = A_{i+1})的情况,可以归纳得出若连续的一段中存在大于等于3种数,则可以任意删除,于是可以DP

    考虑转移需要注意(A_{i-1}= A_{i+1})的地方

    代码

    int a[maxn];
    
    int solve(int l,int r){
        int len = r - l + 1;
        if(len <= 2) return 1;
        VI v(len + 1),pre(len + 1),sum(len + 1),dp(len + 1);
        for(int i = 1;i <= len;i++)
            v[i] = a[l + i - 1];
        pre[1] = 1;
        pre[2] = 1;
        for(int i = 3;i <= len;i++){
            pre[i] = i - 1;
            if(v[i] == v[i - 2]) pre[i] = pre[i - 1];
        }
        dp[1] = dp[2] = sum[1] = 1;
        sum[2] = 2;
        for(int i = 3;i <= len;i++){
            dp[i] = (dp[i - 1] + dp[i - 2]) % MOD;
            add(dp[i],sum[min(i - 2,pre[i]) - 1]);
            sum[i] = (sum[i - 1] + dp[i]) % MOD;
        }
        return dp[len];    
    }
    
    int main(){
        int n = rd();
        for(int i = 1;i <= n;i++)
            a[i] = rd();
        int l = 1;
        int ans = 1;
        for(int i = 1;i < n;i++){
            if(a[i] == a[i + 1])  {
                ans = mul(ans,solve(l,i));
                l = i + 1;
            }
        }
        ans = mul(ans,solve(l,n));
        cout << ans;
    }
    
  • 相关阅读:
    PBRT笔记(3)——KD树
    PBRT笔记(2)——BVH
    PBRT笔记(1)——主循环、浮点误差
    《Ray Tracing in One Weekend》、《Ray Tracing from the Ground Up》读后感以及光线追踪学习推荐
    在Node.js中使用ffi调用dll
    Node.js c++ 扩展之HelloWorld
    在Qt中配置TBB以及简单实用
    对《将Unreal4打包后的工程嵌入到Qt或者桌面中》一文的补充
    QtQuick大坑笔记之Http的Get与Post操作(带cookie)
    QtQuick自定义主题以及控件样式指引
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15426821.html
Copyright © 2011-2022 走看看