• 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

  • 相关阅读:
    新一轮人工智能的兴起引发的思考
    企业应用架构的发展演进
    利用poi插件,把Excel内容读入Java,把Java中的内容输出到Exce
    mysql免安装被指
    正则表达式大全
    开发数据库步骤
    JVM
    Java面试题一
    java集合总结
    JAVA WEB回顾一
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15411187.html
Copyright © 2020-2023  润新知