很需要直觉的一个题,想到关键就很简单了
首先注意到允许输出的数对数量很多,完全不用考虑 \(2\times 10^4\) 的限制,那么直觉就是让每个 pair 产生尽可能少的数
首先考虑怎么能只产生一个数,不妨设这个数为 \(x\),则最小的 pair 只能取 \((3x,2x)\),因此 \(\le \frac{m}{3}\) 的数都是能单独产生的
因此很容易想到把数根据和 \(\frac{m}{3}\) 的大小关系分为两种,对于 \(>\frac{m}{3}\) 的数,手玩一下会发现它们不可能同时出现在生成数列中的前两个位置
因此 \(>\frac{m}{3}\) 的数必然需要和若干个 \(\le \frac{m}{3}\) 的匹配才行,但简单手玩发现选超过两个数显然不如直接选头尾两个数来的优
那么问题转化为一个二分图匹配问题,对于 \(a>\frac{m}{3},b\le\frac{m}{3}\),若 \(2a+b\le m\and b\mid a\),则 \(a\) 向 \(b\) 连一条边
最后看所有 \(>\frac{m}{3}\) 的数是否都能匹配即可,多余的 \(\le \frac{m}{3}\) 的数可以自行处理
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=1005;
typedef pair <int,int> pi;
int n,m,a[N],vis[N],from[N]; vector <int> A,B,v[N];
inline bool find(CI now,CI idx)
{
for (auto to:v[now]) if (vis[to]!=idx)
{
vis[to]=idx;
if (from[to]==-1||find(from[to],idx))
return from[to]=now,1;
}
return 0;
}
signed main()
{
RI i,j; for (scanf("%lld%lld",&n,&m),i=1;i<=n;++i) scanf("%lld",&a[i]);
for (i=1;i<=n;++i) if (3*a[i]<=m) B.push_back(a[i]); else A.push_back(a[i]);
for (i=0;i<A.size();++i) for (j=0;j<B.size();++j)
{
int a=A[i],b=B[j];
if (2*a+b>m||a%b!=0) continue;
v[i].push_back(j);
}
memset(from,-1,sizeof(from));
int res=0; for (i=0;i<A.size();++i) res+=find(i,i+1);
if (res!=A.size()) return puts("-1"),0;
vector <pi> ans;
for (j=0;j<B.size();++j)
{
if (from[j]==-1) { ans.push_back(pi(3*B[j],2*B[j])); continue; }
int a=A[from[j]],b=B[j]; ans.push_back(pi(2*a+b,a+b));
}
printf("%lld\n",(int)ans.size());
for (auto [x,y]:ans) printf("%lld %lld\n",x,y);
return 0;
}
标签:Guess,le,frac,idx,int,CF1684G,now,Euclid,include
From: https://www.cnblogs.com/cjjsb/p/18321580