zoukankan      html  css  js  c++  java
  • P6775 [NOI2020] 制作菜品(dp,bitset)

    传送门


    解题思路

    m:菜数 n:原料数

    • 当 m=n-1 时:最小的跟最大的两两结合。

    • 当 m>=n 时:最大的单独做,最后就变成了 m=n-1 的情况。

    • 当 m=n-2 时:将每个物品减去k后做01可行性背包,可以使用 bitset 优化。

    具体证明可以看这里:题解 P6775 【[NOI2020]制作菜品】

    如何输出路径?

    开n个bitset,第i个表示用前i个物品,然后倒序枚举物品,能转移就转移。

    注意快读和关掉同步不能一块用,否则死循环会T掉?

    AC代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<bitset>
    using namespace std;
    template<class T>inline void read(T &x){
    	cin>>x;
    }
    const int maxn=2500000;
    bitset<maxn*2> dp[505];
    int a[505],vis[505],n,m,k;
    struct node{
    	int v,id;
    }d[505];
    bool cmp1(node a,node b){
    	return a.v<b.v;
    }
    void work1(int n){
    	for(int i=1;i<n;i++){
    		int minn=0,maxx=0;
    		for(int j=1;j<=n;j++){
    			if(d[a[j]].v==0) continue;
    			if(minn==0||d[a[j]].v<d[minn].v) minn=a[j];
    			if(maxx==0||d[a[j]].v>=d[maxx].v) maxx=a[j];
    		}
    		if(d[minn].v==k){
    			cout<<d[minn].id<<' '<<k<<endl;
    			d[minn].v=0;
    		}else{
    			cout<<d[minn].id<<' '<<d[minn].v<<' '<<d[maxx].id<<' '<<k-d[minn].v<<endl;
    			d[maxx].v-=k-d[minn].v;
    			d[minn].v=0;
    		}
    	}
    }
    bool DP(int n){
    	dp[0][maxn]=1; 
    	for(int i=1;i<=n;i++){
    		if(d[i].v>=k) dp[i]=dp[i-1]|(dp[i-1]<<(d[i].v-k));
    		else dp[i]=dp[i-1]|(dp[i-1]>>(-d[i].v+k));
    	}
    	if(!dp[n][maxn-k]) return 0;
    	int now=maxn-k;
    	for(int i=n;i>=1;i--){
    		if(dp[i-1][now-(d[i].v-k)]){
    			vis[i]=1;
    			now-=d[i].v-k;
    		}
    	}
    	return 1;
    }
    int main(){
    	ios::sync_with_stdio(false);
    	int T;
    	cin>>T;
    	while(T--){
    		memset(d,0,sizeof(d));
    		memset(vis,0,sizeof(vis));
    		read(n);read(m);read(k);
    		for(int i=0;i<=n;i++) dp[i].reset();
    		for(int i=1;i<=n;i++) read(d[i].v),d[i].id=i;
    		sort(d+1,d+n+1,cmp1);
    		if(m==n-1){
    			for(int i=1;i<=n;i++) a[i]=i;
    			work1(n);
    		}else if(m>=n){
    			int now=n;
    			while(m!=n-1){
    				if(d[now].v>k) d[now].v-=k;
    				cout<<d[now].id<<' '<<k<<endl;
    				if(d[now].v<=k) now--;
    				m--;
    			}
    			sort(d+1,d+n+1,cmp1);
    			for(int i=1;i<=n;i++) a[i]=i;
    			work1(n);
    		}else{
    			if(!DP(n)){
    				cout<<-1<<endl;
    				continue;
    			}
    			int cnt=0;
    			for(int i=1;i<=n;i++){
    				if(vis[i]){
    					a[++cnt]=i;
    				}
    			}
    			work1(cnt);
    			cnt=0;
    			for(int i=1;i<=n;i++){
    				if(!vis[i]){
    					a[++cnt]=i;
    				}
    			}
    			work1(cnt);
    		}
    	}
    	return 0;
    }
    

    //NOI2020 Day2T1

  • 相关阅读:
    闰年测试
    EditBox的测试用例设计
    测试工程中的评审
    测试框架
    github
    第一次上机实验
    对软件测试的初步认识
    白盒测试
    Date : 日期对象
    C++ 格式化输出 及 输入 流
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15411187.html
Copyright © 2011-2022 走看看