题目链接:https://www.luogu.com.cn/problem/P6775
n种原材料,第i个有di个,m道菜品都需要k个原料而且每道菜最多只能用两种材料。
要求构造方案使得满足条件。
1≤n≤500,n−2≤m≤5000,1≤k≤5000,(∑ni=1di)=m×k
额去年线上赛的时候一点想法都没有是时候轮到我来一雪前耻历(虽然这题还是很难
首先我们注意到一个特殊的条件n−2≤m,看上去没什么想法但是看一下数据范围有n−1=m和n−1≤m两个部分分。
先考虑n−1=m的,就是原料比菜品多一个,那么我们一定有dmin<k而且dmin+dmax>k(n≠2)。
嗯所以我们每次拿最少的一个原料和最多的一个原料做一个菜那么依旧满足n−1=m的条件。
然后考虑n≤m的情况,不难发现肯定有dmax≥k,所以我们直接拿最多的来做一道菜那么要不n−1,m−1要么m−1变成n−1=m的情况。
之后是n−2=m的做法,这个是本题的核心难点。
在洛谷题解上看到过一个有趣的证明,我们可以把原料看成一个点,菜品所用的两个原料看成一条边,那么因为m=n−2所以这张图一定是不连通的,那么至少会被分成两棵树。
发现对于树就是m=n−1的情况,所以其实是相当于我们要把m=n−2的情况分成两个m=n−1的情况。
而且因为m=n−1一定有解所以我们只需要考虑怎么分就好了。
相当于我们要找出一个原料集合S使得
∑i∈Sdi=(|S|−1)k⇒∑i∈S(di−k)=−k
然后直接dp的复杂度是O(Tn2k)的,加个bitset优化就是O(Tn2kw),可以通过本题
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<bitset>
using namespace std;
const int N=510,S=5e6+10,W=2500000;
struct node{
int w,id;
}d[N];
struct cnode{
int a,A,b,B;
}v[N*10];
int T,n,m,k,tot;
bool vis[N];
bitset<S>f[N];
vector<node> u;
bool cmp(node x,node y)
{return x.w<y.w;}
void Add(int a,int A,int b=0,int B=0)
{v[++tot]=(cnode){a,A,b,B};return;}
void solve(int m,vector<node> &d){
int n=d.size();tot=0;
while(m&&m>=n){
sort(d.begin(),d.end(),cmp);
Add(d[n-1].id,k);
d[n-1].w-=k;m--;
if(!d[n-1].w)d.pop_back(),n--;
}
if(m==n-1){
while(m){
sort(d.begin(),d.end(),cmp);swap(d[0],d[n-1]);
Add(d[n-1].id,d[n-1].w,d[0].id,k-d[n-1].w);
d[0].w-=k-d[n-1].w;d.pop_back();n--;m--;
if(!d[0].w)swap(d[0],d[n-1]),d.pop_back(),n--;
}
}
for(int i=1;i<=tot;i++){
if(v[i].b)printf("%d %d %d %d\n",v[i].a,v[i].A,v[i].b,v[i].B);
else printf("%d %d\n",v[i].a,v[i].A);
}
u.clear();return;
}
int main()
{
scanf("%d",&T);
f[0][W]=1;
while(T--){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d",&d[i].w),d[i].id=i;
if(m==n-2){
for(int i=1;i<=n;i++){
int tmp=d[i].w-k;
if(tmp>=0){
f[i]=f[i-1];
f[i]|=(f[i-1]<<tmp);
}
else{
f[i]=f[i-1];
f[i]|=(f[i-1]>>(-tmp));
}
}
if(!f[n][W-k])puts("-1");
else{
memset(vis,0,sizeof(vis));
for(int i=n,z=W-k;i>=1;i--){
int tmp=d[i].w-k;
if(f[i-1][z-tmp])
u.push_back(d[i]),vis[i]=1,z-=tmp;
}
solve(u.size()-1,u);
for(int i=1;i<=n;i++)
if(!vis[i])u.push_back(d[i]);
solve(u.size()-1,u);
}
}
else{
for(int i=1;i<=n;i++)
u.push_back(d[i]);
solve(m,u);
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构