题目

思路来源
乱搞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';
}
}
}