WC 2020 选课(背包)

题目

好自闭啊,5KB的背包鬼知道我经历了什么
L = 40 L = 40 L=40
如果没有物品之间的限制,对于一组可以 O ( n log ⁡ n ) O(n\log n) O(nlogn)贪心求出只有 w = 1 , 2 w=1,2 w=1,2的答案再和 w = 3 w = 3 w=3的合并,注意到我们只需要 m L mL mL个状态,对于多组可以直接 O ( L 2 ) O(L^2) O(L2)合并,所以这部分复杂度是 O ( m L 2 ) O(mL^2) O(mL2)的。(分析其实没有看上去那么简单。)
听说w \leq 5都可以闵科夫斯基和的
有物品的限制就枚举状态后继续做之前的工作,注意能预处理的一定要预处理,然后其实就一点都不卡常。

A C   C o d e \mathcal AC \ Code AC Code

#include<bits/stdc++.h>
#define maxm 50055
#define maxn 500055
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define vc vector
#define vi vc<int>
#define mp make_pair
#define Ct const
#define db double
using namespace std;

namespace IO{
	char cb[1<<16] , *cs=cb,*ct=cb;
	char getc(){ return cs == ct && (ct = (cs = cb) + fread(cb,1,1<<16,stdin),cs == ct) ? 0 : *cs++; }
	template<class T>void read(T &res){
		char ch;bool f=0;
		for(;!isdigit(ch=getc());) if(ch=='-') f = 1;
		for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
		(f) && (res = -res);
	}
};
using IO :: getc;
using IO :: read;

int m,T,p,cus[maxm],tim;
int n[maxm],s[maxm];
int *w[maxm] , *c[maxm];
int dat[200][6];
int id[maxm],hdq[maxm],mus[maxm],*hdl[maxm];
int f[55],g[55],G[55],d[maxm],dp[maxn * 3],dp2[maxn * 3];

int main(){freopen("courses.in","r",stdin);
	freopen("courses.out","w",stdout);
	read(m) , read(T);
	vector<pii >pts;
	rep(i,1,m){
		read(n[i]) , read(s[i]);T -= s[i];
		c[i] = new int [n[i] + 5];
		w[i] = new int [n[i] + 5];
		hdl[i] = new int [n[i] + 5];
		rep(j,1,n[i])
			read(w[i][j]) , read(c[i][j]);
	}
	read(p);
	int il = 1 , ir = m;
	rep(i,0,p-1){
		rep(j,0,4) read(dat[i][j]);
		hdq[dat[i][1]] = hdq[dat[i][3]] = 1;
		hdl[dat[i][1]][dat[i][2]] = 
		hdl[dat[i][3]][dat[i][4]] = 1;
		pts.push_back(mp(dat[i][1] , dat[i][2]));
		pts.push_back(mp(dat[i][3] , dat[i][4]));
		if(dat[i][0] != 3) read(dat[i][5]);
	}
	sort(pts.begin(),pts.end());
	pts.resize(unique(pts.begin(),pts.end())-pts.begin());
	rep(i,1,m) if(hdq[i]) id[ir--] = i;
		else id[il++] = i;
	memset(f,0x3f,sizeof f);
	f[0] = 0;
	int sm = 0;
	rep(i,1,ir){
		int u = id[i];
		vector<int>s[4];
		rep(j,1,n[u]) s[w[u][j]].push_back(c[u][j]);
		sort(s[1].begin(),s[1].end());
		sort(s[2].begin(),s[2].end());
		sort(s[3].begin(),s[3].end());
		rep(i,0,::s[u] + 45) dp[i] = 0x3f3f3f3f;
		dp[0] = 0;
		for(int i=2,a=0,b=0;a+1 < s[1].size() || b < s[2].size();i+=2){
			if(b >= s[2].size() || (a+1 < s[1].size() && s[1][a] + s[1][a+1] < s[2][b]))
				dp[i] = dp[i-2] + s[1][a] + s[1][a+1] , a += 2;
			else 
				dp[i] = dp[i-2] + s[2][b++];
		}
		if(!s[1].empty()){
			dp[1] = s[1][0];
			for(int i=3,a=1,b=0;a+1 < s[1].size() || b < s[2].size();i+=2){
				if(b >= s[2].size() || (a+1 < s[1].size() && s[1][a] + s[1][a+1] < s[2][b]))
					dp[i] = dp[i-2] + s[1][a] + s[1][a+1] , a += 2;
				else 
					dp[i] = dp[i-2] + s[2][b++];
			}
		}
		bool flg = 0;
		static int tf[55];
		memset(tf,0x3f,sizeof tf);
		rep(j,0,45){
			int a = dp[j + ::s[u]] , b= 0 ;
			for(int k=0;k<=s[3].size() && 3 * k <= j + ::s[u];k++){
				a = min(a , dp[j + ::s[u] - 3 * k] + b);
				if(k < s[3].size())b += s[3][k];
			}
			per(k,45,0)
				tf[min(k+j,45)] = min(tf[min(k+j,45)] , f[k] + a);
		}
		memcpy(f,tf,sizeof f);
	}
	memset(G,0x3f,sizeof G);
	static int dp[13][maxn],pg[13][200];
	vector<int>s[13][4];
	rep(i,il,m){	
		int u = id[i] , p = i - il;
		rep(j,1,n[u]) if(!hdl[u][j]) s[p][w[u][j]].push_back(c[u][j]);
			sort(s[p][1].begin(),s[p][1].end());
			sort(s[p][2].begin(),s[p][2].end());
			sort(s[p][3].begin(),s[p][3].end());
			rep(i,0,::s[u] + 90) dp[p][i] = 0x3f3f3f3f;
			dp[p][0] = 0;
			for(int i=2,a=0,b=0;a+1 < s[p][1].size() || b < s[p][2].size();i+=2){
				if(b >= s[p][2].size() || (a+1 < s[p][1].size() && s[p][1][a] + s[p][1][a+1] < s[p][2][b]))
					dp[p][i] = dp[p][i-2] + s[p][1][a] + s[p][1][a+1] , a += 2;
				else 
					dp[p][i] = dp[p][i-2] + s[p][2][b++];
			}
			if(!s[p][1].empty()){
				dp[p][1] = s[p][1][0];
				for(int i=3,a=1,b=0;a+1 < s[p][1].size() || b < s[p][2].size();i+=2){
					if(b >= s[p][2].size() || (a+1 < s[p][1].size() && s[p][1][a] + s[p][1][a+1] < s[p][2][b]))
						dp[p][i] = dp[p][i-2] + s[p][1][a] + s[p][1][a+1] , a += 2;
					else 
						dp[p][i] = dp[p][i-2] + s[p][2][b++];
				}
			}
			memset(pg[p],0x3f,sizeof pg[p]);
			rep(j,max(-::s[u],-36),45){
				int a = dp[p][j + ::s[u]] , b = 0;
				for(int k=0;k<=s[p][3].size() && 3 * k <= j + ::s[u];k++){	
					a = min(a , dp[p][j + ::s[u] - 3 * k] + b);
					if(k < s[p][3].size()) b += s[p][3][k];
				}
				pg[p][j + 36] = a;
			}
	}
	
	rep(sta,0,(1<<pts.size())-1){
		bool flg = 0;
		memset(g,0x3f,sizeof g);
		g[0] = 0;
		rep(i,il,m) d[id[i]] = 0;
		rep(i,0,p-1){
			int u = lower_bound(pts.begin() , pts.end() , mp(dat[i][1] , dat[i][2])) - pts.begin() ,
				v = lower_bound(pts.begin() , pts.end() , mp(dat[i][3] , dat[i][4])) - pts.begin();
			if((sta >> u & 1) && (sta >> v & 1)){
				if(dat[i][0] == 3){ flg = 1; break;}
				if(dat[i][0] == 1) g[0] -= dat[i][5];
				if(dat[i][0] == 2) g[0] += dat[i][5];
			}
		}
		if(flg) continue;
		rep(i,0,pts.size() - 1) if(sta >> i & 1)
			d[pts[i].first] += w[pts[i].first][pts[i].second] , 
			g[0] += c[pts[i].first][pts[i].second];
		rep(i,il,m){
			int u = id[i] , p = i - il;
			
			static int tg[55];
			memset(tg,0x3f,sizeof tg);
			rep(j,max(-d[u],-::s[u]),45){
				
				per(k,45,0)
					tg[min(k+j+d[u],45)] = min(tg[min(k+j+d[u],45)] , g[k] + pg[p][j + 36]);
			}
			memcpy(g,tg,sizeof g);
		}
		rep(i,0,45) G[i] = min(G[i] , g[i]);
	}
	int ans = 0x3f3f3f3f;
	rep(i,0,45) rep(j,0,45)
		if(i + j >= T)
			ans = min(ans , f[i] + G[j]);
	if(ans >= 0x3f3f3f3f) ans = -1;
	printf("%d\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值