22.2.26_周六

D - Three Integers

题意:

给你三个数每次可以对这三个数a , b , c的其中一个数进行加一或减一的操作 求最小操作次数 使得c能被b整除 b能被a整除

思路:

暴力模拟来求 很容易知道c不可能增大到2*c 因为前两个数都比c小 可以减小前两个数 若将c增到了2*c操作次数肯定不是最优的 a, b, c最大能取到1e4 并没有很大 况且是乘着遍历 故不会超时

时间复杂度是 O(2*(logn)*n)

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f; 
int  a, b, c;
int aa, bb, cc, ans; 

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t; 
    cin >> t;
    while (t --){
        ans = inf;
        cin >> a >> b >> c;    
        for(int i = 1; i <= 2 * c; i++){//i代表a的值
            for(int  j = 1; j * i <= 2 * c; j++){
                for(int k = 1; k * i * j <= 2 * c; k++){
                    int sum = abs(i - a) + abs(i * j - b) + abs(i * j * k - c);
                    if(sum < ans){//如果操作次数会更小 就同步更新数据
                        aa = i;
                        bb = i * j;
                        cc = i * j * k;
                        ans = sum;
                    }
                }
            }
        }
        cout << ans << "\n";
        cout << aa << " " << bb << " " << cc << "\n";
    }
    return 0;
}

 

 

E - Construct the Binary Tree

 题意:

给你n个点和一个数 求能否创建一颗二叉树使得每个点到起始点的最深路径和为d 输出yes或no 如果是yes 再输出第2~n个点的父亲结点

思路:

首先可以想到最大的路径和是一条长链 而 最小的路径是 满二叉树 我们先将它们连成长链 再将结点往前移 一步一步向前太费时间 可以直接比较移到尽可能最前面的步数和路径达到d所要步数 取较小值 直接移到pos - res处 应为要记录父亲结点 用val[i][j]储存第i层第j个的序号信息 再用cnt[ ]数组记入每层的个数 利用二叉树的性质容易得到 当前层第i个数的父亲结点是上一层第i/2个数 然后还要注意像一层个数不能超过前一层个数的两倍

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f; 
int  n, d, dis, cnt[N], fa[N], val[5010][5010];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t; 
    cin >> t;
    while (t --){
        cin >> n >> d;
        int dis = (n - 1) * n / 2;
        if(d > dis) cout << "NO" << "\n";
        else{
            for(int i = 1; i <= n; i++){
                cnt[i] = 1;
                fa[i] = i - 1;
                val[i][1] = i;
            }
            int pre = 2;
            for(int i = n; i > 1; i--){
                int pos = i;
                if(dis > d && pos >= 3){
                    int res = min(dis - d, pos - pre);//可以跳的最大步数
                    dis -= res;//总路径减少
                    val[pos - res][++cnt[pos - res]] = pos;//跳转后更新二叉树
                    fa[pos] = val[pos - res - 1][(cnt[pos - res] + 1) / 2];//当前层第x个数是上一层第x/2个数的儿子
                    if(cnt[pre] == 2 * cnt[pre - 1]){//当该层已满即达到上一层的两倍 最远只能达到下一层了
                        pre ++;
                    }
                }
                else break;
            }
            if(dis == d) {
                cout << "YES\n";
                for(int i = 2; i <= n; i++){
                    cout << fa[i] << " \n"[i == n];
                }
            }
            else cout << "NO\n";
        }
    }
    return 0;
}

 

posted @ 2022-02-26 20:59  Yaqu  阅读(29)  评论(0)    收藏  举报