• P6775 [NOI2020] 制作菜品


    题目大意

    厨师准备给小朋友们制作 m m m 道菜,每道菜均使用 k k k 克原材料。为此,厨师购入了 n n n 种原材料,原材料从 1 1 1 n n n 编号,第 i i i 种原材料的质量为 d i d_i di 克。 n n n 种原材料的质量之和恰好为 m × k m \times k m×k,其中 d i d_i di k k k 都是正整数
    制作菜品时,一种原材料可以被用于多道菜,但为了让菜品的味道更纯粹,厨师打算每道菜至多使用 2 2 2原材料。现在请你判断是否存在一种满足要求的制作方案。更具体地,方案应满足下列要求:

    • 共做出 m m m 道菜。
    • 每道菜至多使用 2 2 2 种原材料。
    • 每道菜恰好使用 k k k 克原材料。
    • 每道菜使用的每种原材料的质量都为正整数克。
    • n n n 种原材料都被恰好用完。
      若存在满足要求的制作方案,你还应该给出一种具体的制作方案。

    1 ≤ n ≤ 500 1 \leq n \leq 500 1n500 n − 2 ≤ m ≤ 5000 n - 2 \leq m \leq 5000 n2m5000 m ≥ 1 m \geq 1 m1 1 ≤ k ≤ 5000 1 \leq k \leq 5000 1k5000 ∑ i = 1 n d i = m × k \sum_{i=1}^{n}d_i = m \times k i=1ndi=m×k

    题解

    好题!
    首先观察数据范围,发现 m ≥ n − 2 m\ge n-2 mn2,就知道这题应该是什么分类讨论题了
    再观察细致的数据范围,发现有 m = n − 1 m=n-1 m=n1 m ≥ n − 1 m\ge n-1 mn1的部分分,所以从 m = n − 1 m=n-1 m=n1下手,先把 d d d数组排序,有结论 d 1 + d n ≥ k d_1+d_n\ge k d1+dnk,然后我们用 1 1 1 n n n做一道菜,把 1 1 1用完,然后就变成了一个 m − 1 , n − 1 m-1,n-1 m1,n1的规模更小的数据范围,当 m = 2 , n = 1 m=2,n=1 m=2,n=1时显然有解,所以 m = n − 1 m=n-1 m=n1时有解, m > n − 1 m>n-1 m>n1时,显然有 d n ≥ k d_n\ge k dnk,然后不停地用 d n d_n dn做菜,显然可以归约到 m = n − 1 m=n-1 m=n1的情况
    然后就只剩下 m = n − 2 m=n-2 m=n2的情况了,手玩一下小数据进行观察, n = 3 n=3 n=3时无解, n = 4 n=4 n=4的充要条件为两个 d d d的和等于 k k k,这启发我们把 m = n − 2 m=n-2 m=n2的情况划分成两个 m = n − 1 m=n-1 m=n1的情况
    结论: { d n } \{d_n\} {dn}有解当且仅当,可以划分成一个子集 S ⊂ { 1 , 2 , ⋯   , n } S\subset\{1,2,\cdots,n\} S{1,2,,n},使得 ∑ i ∈ S d i = ( ∣ S ∣ − 1 ) k \sum_{i\in S}d_i=(|S|-1)k iSdi=(S1)k
    充分性:这个子集和它的补集可以形成两个 m = n − 1 m=n-1 m=n1的问题,所以肯定有解
    必要性:如果两个原料做了一道菜,我们就给这两个原料连上一条边,由于 m = n − 2 m=n-2 m=n2,所以这个图肯定不连通,解必定有办法划分成两个连通的图
    这个可以用 01 01 01背包来判断,用 b i t s e t bitset bitset优化,复杂度就变成了 O ( n 2 k w ) O(\frac{n^2k}{w}) O(wn2k)

    code

    #include
    #include
    #include
    #include
    #include
    using namespace std;
    void read(int &res)
    {
    	res=0;char ch=getchar();
    	while(ch<'0'||ch>'9') ch=getchar();
    	while('0'<=ch&&ch<='9') res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    }
    const int N=5e2+10,K=5e3+10;
    int n,m,k,d[N+10];
    struct node
    {
    	int id,d;
    }p[N+10];
    void write(int res)
    {
    	if(res>=10) write(res/10),putchar('0'+res%10);
    	else putchar('0'+res);
    }
    namespace sub1
    {
    	bool cmp(node a,node b){return a.d<b.d;}
    	void solve(int n)
    	{
    		for(int i=1;i<=n;i++)
    			while(m>n-1&&p[i].d>=k)
    			{
    				write(p[i].id),putchar(' '),write(k),putchar('\n');
    				p[i].d-=k;
    				m--;
    			}
    		for(int i=n;i>=2;i--)
    		{
    			sort(p+1,p+1+i,cmp);
    			if(p[1].d==0) write(p[i].id),putchar(' '),write(k-p[1].d),putchar('\n');	
    			else write(p[1].id),putchar(' '),write(p[1].d),putchar(' '),write(p[i].id),putchar(' '),write(k-p[1].d),putchar('\n');
    			p[i].d-=k-p[1].d,p[1]=p[i];
    		}
    	}
    }
    namespace sub2
    {
    	bitset<N*K*2+10> f[N+10];
    	bool vis[N+10];
    	const int C=N*K;
    	void dfs(int h,int s)
    	{
    		if(h==0) return;
    		if(s+C-(d[h]-k)>=0&&s+C-(d[h]-k)<=C*2&&f[h-1][s+C-(d[h]-k)]) vis[h]=true,dfs(h-1,s-(d[h]-k));
    		else dfs(h-1,s);
    	}
    	void solve()
    	{
    		f[0].reset(),f[0].set(k+C);
    		for(int i=1;i<=n;i++)
    		{
    			if(d[i]-k>=0) f[i]=f[i-1]|(f[i-1]<<d[i]-k);
    			else f[i]=f[i-1]|(f[i-1]>>k-d[i]);
    		}
    		if(!f[n][C]) printf("-1\n");
    		else
    		{
    			for(int i=1;i<=n;i++) vis[i]=false;
    			dfs(n,0);
    			int top=0;
    			for(int i=1;i<=n;i++)
    				if(vis[i])
    					p[++top]=(node){i,d[i]};
    			m=top-1;
    			sub1::solve(top);
    			top=0;
    			for(int i=1;i<=n;i++)
    				if(!vis[i])
    					p[++top]=(node){i,d[i]};
    			m=top-1;
    			sub1::solve(top);
    		}
    	}
    }
    int main()
    {
    	freopen("dish.in","r",stdin);
    	freopen("dish.out","w",stdout);
    	int T;
    	read(T);
    	for(;T--;)
    	{
    		read(n),read(m),read(k);
    		for(int i=1;i<=n;i++) read(d[i]);
    		if(m>=n-1)
    		{
    			for(int i=1;i<=n;i++) p[i].d=d[i],p[i].id=i;
    			sub1::solve(n);
    		}
    		else sub2::solve();
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
  • 相关阅读:
    DRM全解析 —— ADD_FB2(5)
    JVM吞吐量与延迟关系
    软考——软件设计师中级2023年11月备考(1.计算机组成原理)
    生成可信任的https证书-use
    安全带佩戴识别高空作业
    axios的详细使用
    Centos 7 - uWSGI服务器 虚拟环境配置详解及 .ini 文件配置模板 - No module named ‘encodings - uWSGI服务器无法识别虚拟环境内的python解释器
    MVC与三层架构
    JDK1.8下载、安装和环境配置教程
    nginx实现反向代理实例
  • 原文地址:https://blog.csdn.net/Z_Y_S_/article/details/126293602