2026牛客寒假算法基础集训营3 E. 躯树の墓守(构造)

题目

思路来源

乱搞ac

题解

sum下界是易得的,1,2,3,...,n-1即可,记为序列a,

手玩发现,对于sum=14的情况,1 2 4 7显然是比1 2 3 8优的,

其中4、5、6、7需要浪费四条边,而1、2、3连接了三个点后,只能浪费三条边

也就是,对于要浪费的权值来说,能早浪费就早浪费,

那么,浪费完之后形成一个团之后,后面权值最小的边一定是要取的,

也就是权值序列形成了这样一个序列,

对应,先求出这样一个长度为n-1的序列,

然后因为有m的限制,再倒着遍历一遍,

最后一项和m取min,倒数第二项和m-1取min,以此类推,

得到的新序列,就是满足上界约束下,能得到的最大sum对应的序列,

也就得到了上界,记为序列b,这样最终答案的每一项只能落在[ai,bi]之间

这样在上下界之间的序列就都可以得到了,

初始时令最终序列c=a,然后考虑当前所求x和最大上界sum的差值delta,

再倒着贪心一遍,每一项最多可以加上b[i]-a[i],并且后面的加的一定大于等于前面的,

这样就能保证答案一定可以构造出来,并且构造之后还是一个增序序列

最后树边就1连2,2连3,3连4,...,n-1连n串成一条链,其他的边选一下凑够m条即可

自己赛中写的实际是模拟了这个过程,比较麻烦,看到sserxhs的代码茅塞顿开

代码1(自己写的)

cpp 复制代码
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef array<int,3> A;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
using namespace std;
const int N=2e5+10;
int t,n,m,k;
ll lb,ub;
vector<A>res;
bool used[N];
bool sol(){
    ll lb=1ll*n*(n-1)/2;
    if(k<lb)return 0;
    vector<int>ans;
    int mx=k-(n-1)*(n-2)/2;
    //printf("mx:%d\n",mx);
    int ban=mx-(n-1);
    int del=0,val=1;
    rep(i,1,n-2){
        int ver=i+1,all=1ll*ver*(ver-1)/2-i;
        ans.pb(val++);
        //printf("i:%d all:%d\n",i,all);
        if(i==n-2)break;
        while(del<all){
            int left=n-2-i;
            int mx2=val+left;
            //printf("i:%d del:%d all:%d mx:%d mx2:%d left:%d val:%d\n",i,del,all,mx,mx2,left,val);
            if(mx-left>mx2){
                mx-=left;
                val++;
                del++;
            }
            else{
                break;
            }
        }
    }
    //puts("gg2");
    ans.pb(mx);
    if(mx>m)return 0;
    //printf("mx:%d\n",mx);
    rep(i,1,m)used[i]=0;
    for(auto &v:ans){
        //printf("v:%d\n",v);
        used[v]=1;
    }
    int c=1;
    vector<P>no;
    rep(i,1,m){
        if(used[i]){
            c++;
            res.pb({c-1,c,i});
            for(int j=1;j<c-1;++j){
                if(SZ(no)>m)break;
                no.pb(P(j,c));
            }
        }
        else{
            if(no.empty())return 0;
            P x=no.back();no.pop_back();
            res.pb({x.fi,x.se,i});
        }
    }
    return 1;
    //1 2 ... n-3 n-2 mx
}
int main(){
    sci(t);
    while(t--){
        sci(n),sci(m),sci(k);
        if(!sol()){
            puts("NO");
        }
        else{
            puts("YES");
            for(auto &x:res){
                printf("%d %d %d\n",x[0],x[1],x[2]);
            }
            res.clear();
        }
    }
    return 0;
}

代码2(SSerxhs写法)

cpp 复制代码
//这回只花了114514min就打完了。
//真好。记得多手造几组。ACM拍什么拍。 
#include "bits/stdc++.h"
using namespace std;
using ui = unsigned; using db = long double; using ll = long long; using ull = unsigned long long;
template<class T1, class T2> istream &operator>>(istream &cin, pair<T1, T2> &a) { return cin >> a.first >> a.second; }
template <std::size_t Index = 0, typename... Ts> typename std::enable_if<Index == sizeof...(Ts), void>::type tuple_read(std::istream &is, std::tuple<Ts...> &t) { }
template <std::size_t Index = 0, typename... Ts> typename std::enable_if < Index < sizeof...(Ts), void>::type tuple_read(std::istream &is, std::tuple<Ts...> &t) { is >> std::get<Index>(t); tuple_read<Index + 1>(is, t); }
template <typename... Ts>std::istream &operator>>(std::istream &is, std::tuple<Ts...> &t) { tuple_read(is, t); return is; }
template<class T1> istream &operator>>(istream &cin, valarray<T1> &a);
template<class T1> istream &operator>>(istream &cin, vector<T1> &a) { for (auto &x : a) cin >> x; return cin; }
template<class T1> istream &operator>>(istream &cin, valarray<T1> &a) { for (auto &x : a) cin >> x; return cin; }
template<class T1, class T2> bool cmin(T1 &x, const T2 &y) { if (y < x) { x = y; return 1; } return 0; }
template<class T1, class T2> bool cmax(T1 &x, const T2 &y) { if (x < y) { x = y; return 1; } return 0; }
template<class T1> vector<T1> range(T1 l, T1 r, T1 step = 1) { assert(step > 0); int n = (r - l + step - 1) / step, i; vector<T1> res(n); for (i = 0; i < n; i++) res[i] = l + step * i; return res; }
template<class T1> basic_string<T1> operator*(const basic_string<T1> &s, int m) { auto r = s; m *= s.size(); r.resize(m); for (int i = s.size(); i < m; i++) r[i] = r[i - s.size()]; return r; }
using lll = __int128;
istream &operator>>(istream &cin, lll &x) { bool flg = 0; x = 0; static string s; cin >> s; if (s[0] == '-') flg = 1, s = s.substr(1); for (char c : s) x = x * 10 + (c - '0'); if (flg) x = -x; return cin; }
ostream &operator<<(ostream &cout, lll x) { static char s[60]; if (x < 0) cout << '-', x = -x; int tp = 1; s[0] = '0' + (x % 10); while (x /= 10) s[tp++] = '0' + (x % 10); while (tp--) cout << s[tp]; return cout; }
#if !defined(ONLINE_JUDGE)&&defined(LOCAL)
#include "my_header/debug.h"
#else
#define dbg(...) 0
#endif
template<class T1, class T2> ostream &operator<<(ostream &cout, const pair<T1, T2> &a) { return cout << a.first << ' ' << a.second; }
template<class T1, class T2> ostream &operator<<(ostream &cout, const vector<pair<T1, T2>> &a) { for (auto &x : a) cout << x << '\n'; return cout; }
template<class T1> ostream &operator<<(ostream &cout, vector<T1> a) { int n = a.size(); if (!n) return cout; cout << a[0]; for (int i = 1; i < n; i++) cout << ' ' << a[i]; return cout; }
template<class T1> ostream &operator<<(ostream &cout, const valarray<T1> &a) { int n = a.size(); if (!n) return cout; cout << a[0]; for (int i = 1; i < n; i++) cout << ' ' << a[i]; return cout; }
template<class T1> ostream &operator<<(ostream &cout, const vector<valarray<T1>> &a) { int n = a.size(); if (!n) return cout; cout << a[0]; for (int i = 1; i < n; i++) cout << '\n' << a[i]; return cout; }
template<class T1> ostream &operator<<(ostream &cout, const vector<vector<T1>> &a) { int n = a.size(); if (!n) return cout; cout << a[0]; for (int i = 1; i < n; i++) cout << '\n' << a[i]; return cout; }
#define all(x) (x).begin(),(x).end()
#define print(...) cout<<format(__VA_ARGS__)
#define println(...) cout<<format(__VA_ARGS__)<<'\n'
#define err(...) cerr<<format(__VA_ARGS__)
#define errln(...) cerr<<format(__VA_ARGS__)<<'\n'
#define func(name, ret, ...) function<ret(__VA_ARGS__)> name = [&]( __VA_ARGS__ )
int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    cout << fixed << setprecision(15);
    int T; cin >> T;
    while (T--)
    {
        int n, m, i, j;
        ll q;
        cin >> n >> m >> q;
        vector<int> a(n);
        for (i = 1; i < n; i++) a[i] = min<ll>(m, i * (i - 1ll) / 2 + 1);
        for (i = n - 1; i > 1; i--) cmin(a[i - 1], a[i] - 1);
        // dbg(a);
        if (q<n * (n - 1ll) / 2 || q>reduce(all(a), 0ll))
        {
            cout << "NO\n";
            continue;
        }
        vector<int> b(n);
        for (i = 1; i < n; i++) b[i] = i, q -= i;
        for (i = n - 1; i; i--)
        {
            ll d = min<ll>(q, a[i] - b[i]);
            b[i] += d;
            q -= d;
        }
        cout << "YES\n";
        int x = 3, y = 1;
        vector<pair<int, int>> eg;
        for (i = 1, j = 1; i < n; i++)
        {
            while (j < b[i])
            {
                assert(x <= i);
                eg.push_back({x, y});
                ++y;
                if (y == x - 1) ++x, y = 1;
                ++j;
            }
            eg.push_back({i, i + 1});
            ++j;
        }
        while (j <= m)
        {
            assert(x <= n);
            eg.push_back({x, y});
            ++y;
            if (y == x - 1) ++x, y = 1;
            ++j;

        }
        for (i = 0; i < m; i++)
        {
            auto [u, v] = eg[i];
            cout << u << ' ' << v << ' ' << i + 1 << '\n';
        }
    }
}
相关推荐
寻寻觅觅☆9 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
偷吃的耗子10 小时前
【CNN算法理解】:三、AlexNet 训练模块(附代码)
深度学习·算法·cnn
2013编程爱好者10 小时前
【C++】树的基础
数据结构·二叉树··二叉树的遍历
NEXT0610 小时前
二叉搜索树(BST)
前端·数据结构·面试
化学在逃硬闯CS10 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
ceclar12311 小时前
C++使用format
开发语言·c++·算法
Gofarlic_OMS11 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
夏鹏今天学习了吗11 小时前
【LeetCode热题100(100/100)】数据流的中位数
算法·leetcode·职场和发展
忙什么果12 小时前
上位机、下位机、FPGA、算法放在哪层合适?
算法·fpga开发
董董灿是个攻城狮12 小时前
AI 视觉连载4:YUV 的图像表示
算法