[NOI2020]制作菜品
链接:https://www.luogu.com.cn/problem/P6775
题目描述:有道菜,和种原材料,每个原材料有一个质量,有(m为正整数),每次在道菜中选一部分满足质量总和为,求一组合法方案。
题解:考场上想了会了,结果判错成。
假如我们已经选定好了一种方案,那么我们可以考虑如何判定合法性,我们可以建出网络流模型,然后两边跑最大流,判是否满流。
但是我们会发现,若现在的判定方案为,在跑网络流的时候,对于,我们可以将它流掉,那么它一定可以被单独做为道菜流,所以我们可以将它流掉。
考虑流掉后的范围,若,由于有,那么,又有,则,所以对于可以归纳为。
那么考虑如何构造一组的方案,可以如下构造方案:
先处理个数,将最小的元素与最大的元素匹配从而消去最小的元素,这样就消去了一个数,然后对于剩下的数反复该过程。
考虑如何证明,令从小到大排序后为,则最小的数为,最大的数为,那么因,则若,那么有,则矛盾,即,可以构造出一组方案。
那么对于的情况,我们发现无法归纳解决,那么仔细观察可以发现有解时的解中一定会有两个不连通的。
考虑如何证明。由于拆时将其拆为连通图,那么这些图都有,那么若对于一个点数为,边数为的连通图,若,则即可归纳为的问题,一定存在解。反之,则会无法恰好选完,则无解。
即为连通图有解的充要条件。
那么考虑我们的解是若干个连通图,每个图需满足上述条件,在这些图会存在一些带环图与树,那么将带环图与树合并,合并出的新连通图仍满足这个条件,那么合并会更优,在合并完后会合并成两颗无法合并的树,所以有解时一定会有两个不连通的。
那么我们可以构造一颗树,另外一颗树就满足条件,即需构造,这个可化为,将看作元素可以背包,转移时可用优化转移。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<bitset>
using namespace std;
int read()
{
char c=0;
int sum=0;
while (c<'0'||c>'9')
c=getchar();
while ('0'<=c&&c<='9')
sum=sum*10+c-'0',c=getchar();
return sum;
}
struct node
{
int num,d;
bool operator < (const node &a)const
{
return d<a.d;
}
};
node point[501],tong[501];
int T,n,m,k,cnt,length,maxer,maxn;
bool used[501];
bitset<4980001>dp[501];
int main()
{
bool op;
T=read();
while (T--)
{
n=read(),m=read(),k=read();
for (int i=1;i<=n;++i)
point[i].num=i,point[i].d=read();
if (m>=n-1)
{
cnt=0;
for (int i=1;i<=n;++i)
while (point[i].d>=k&&cnt<m-n+1)
cnt++,point[i].d-=k,printf("%d %d\n",point[i].num,k);
for (int t=1;t<=n;++t)
{
sort(point+t,point+n+1);
if (point[t].d==0)
continue;
if (point[t].d==k)
{
printf("%d %d\n",point[t].num,k);
continue;
}
printf("%d %d %d %d\n",point[t].num,point[t].d,point[n].num,k-point[t].d);
point[n].d-=(k-point[t].d);
}
}
else
{
for (int i=1;i<=n;++i)
used[i]=0;
for (int i=0;i<=n;++i)
dp[i].reset();
dp[0][(n-2)*k]=1;
int s,ps,tmp;
op=0;
for (int i=1;i<=n;++i)
{
if (k-point[i].d>=0)
dp[i]=dp[i-1]|(dp[i-1]<<(k-point[i].d));
else
dp[i]=dp[i-1]|(dp[i-1]>>(point[i].d-k));
if (dp[i][k+(n-2)*k])
{
op=1;
used[i]=1,s=k+(n-2)*k-(k-point[i].d),ps=i;
while (ps!=0)
{
tmp=ps;
for (int j=0;j<=tmp-1;++j)
if (dp[j][s])
{
ps=j;
break;
}
used[ps]=1;
s=s-(k-point[ps].d);
}
break;
}
}
if (op)
{
length=0;
for (int i=1;i<=n;++i)
if (used[i])
tong[++length]=point[i];
for (int t=1;t<=length;++t)
{
sort(tong+t,tong+length+1);
if (tong[t].d==0)
continue;
printf("%d %d %d %d\n",tong[t].num,tong[t].d,tong[length].num,k-tong[t].d);
tong[length].d-=(k-tong[t].d);
}
length=0;
for (int i=1;i<=n;++i)
if (!used[i])
tong[++length]=point[i];
for (int t=1;t<=length;++t)
{
sort(tong+t,tong+length+1);
if (tong[t].d==0)
continue;
printf("%d %d %d %d\n",tong[t].num,tong[t].d,tong[length].num,k-tong[t].d);
tong[length].d-=(k-tong[t].d);
}
}
else
puts("-1");
}
}
return 0;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983765.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】