2019-2020 SEERC 2019

B Level Up

一个背包dp,每个点有选和不选的状态设dp[i][j][k]前i个第一级经验为j,第二级经验为k时的最小时间。

把所有点按s1从小到大排序,这样就不会漏掉方案而且s2经验槽先后顺序也没有了

这样可以先选择s2,只要s1溢出的时候加到s2上面就行了,而不是只有等s1选满才能选s2,想到这就是简单的dp了

[egin{array} if quad j+a[i].w1>s1 \ quad dp[i+1][s1][k+j+a[i].w1-s1]=min(dp[i][j][k]+a[i].t1,dp[i+1][s1][k+j+a[i].w1-s1]);\ if quad j==s1 \ quad dp[i+1][s1][k+a[i].w2]=min(dp[i][j][k]+a[i].t2,dp[i+1][s1][k+a[i].w2]); end{array} ]

然后发现爆空间了

(常规的滚动数组优化|两个for循环状态转移就行了

代码

#include<bits/stdc++.h>
using namespace std;
const int N=500+5;
long long inf=1e18;
int n,s1,s2,x,y,t,r;
long long ans[N][N],dp[N][N];
struct node
{
    int t1,w1;
    int t2,w2;
}a[N];
bool cmp(node q,node p)
{
    return q.w1<p.w1;
}

int main()
{
    scanf("%d %d %d",&n,&s1,&s2);
    for(int i=1;i<=n;i++)
    {
        scanf("%d %d %d %d",&a[i].w1,&a[i].t1,&a[i].w2,&a[i].t2);
    }   
    sort(a+1,a+n+1,cmp);
	for(int i=0;i<=s1;i++)
	{
		for(int j=0;j<=s2;j++)
			ans[i][j]=inf;
	
	}
	ans[0][0]=0;
	for(int i=1;i<=n;i++)
	{
		// dp[i][j][k]=dp[i-1][j][k]	
		for(int j=0;j<=s1;j++)
		{
			for(int k=0;k<=s2;k++)
				dp[j][k]=ans[j][k];
		}
		for(int j=s1;j>=0;j--)
		{
			for(int k=s2;k>=0;k--)
			{
				if(j+a[i].w1<=s1)
				{
					dp[j+a[i].w1][k]=min(dp[j][k]+a[i].t1,dp[j+a[i].w1][k]);
				}
				else
				{
					if(j!=s1)
						dp[s1][min(k+j+a[i].w1-s1,s2)]=min(dp[s1][min(s2,k+j+a[i].w1-s1)],dp[j][k]+a[i].t1);	
				}
				dp[j][min(k+a[i].w2,s2)]=min(dp[j][k]+a[i].t2,dp[j][min(k+a[i].w2,s2)]);
			}
		}
		for(int j=0;j<=s1;j++)
		{
			for(int k=0;k<=s2;k++)
				ans[j][k]=dp[j][k];
		}
	}
	if(ans[s1][s2]==inf)
		printf("-1
");
	else
		printf("%lld
",ans[s1][s2]);
    return 0;
}
/*
2 100 100
100 100 10 10
101 11 100 10
*/

Life Transfer

每个摩托只能载一个人!!!(常识使我觉得摩托能载两个人…自闭好久)

首先前缀和预处理:

[egin{cases} pro_sumc[i]&前i个人大于车的年龄数\ pro_summ[i]&前i个人大于摩托年龄数\ need_sumc[i]&前i个人全开车需要的年龄数\ need_summ[i]&前i个人全骑摩托需要的年龄数\ end{cases} ]

然后枚举汽车的数量,则摩托的数量是一定的,年龄从大到小排序然后贪心就行了
(如果lc>lm先把car安排好肯定能消耗更少的魔法次数否则先排摩托肯定能消耗更少的魔法次数)

最后再特判一下全安排汽车的情况的费用就行了(代码写的好也可以一个循环里面完事)

pm,pc必须开longlong否则会过不了,坑我几个小时

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
const long long inf=__LONG_LONG_MAX__;
long long n,k,lc,lm,t,d,a[N];
long long pc,pm ;
long long ans=inf;
long long pro_sumc[N],pro_summ[N],need_sumc[N],need_summ[N];
bool cmp(int x,int y)
{
	return x>y;
}
int main()
{
	scanf("%lld %lld",&n,&k);
	scanf("%lld %lld %lld %lld",&lc,&pc,&lm,&pm);
    \ pm pc 不开longlong过不了不知道为什么
	scanf("%lld %lld",&t,&d);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		//前i个能供给的年龄
		pro_sumc[i]=pro_sumc[i-1]+max(a[i]-lc,(long long)0);
		pro_summ[i]=pro_summ[i-1]+max(a[i]-lm,(long long )0);
		//前i个变得能骑车需要的年龄
		need_sumc[i]=need_sumc[i-1]+max(lc-a[i],(long long )0);
		need_summ[i]=need_summ[i-1]+max(lm-a[i],(long long )0);
		//printf("i:%d %d %d %d %d
",i,pro_sumc[i],pro_summ[i],need_sumc[i],need_summ[i]);
	}
	
	long long sum=0;
	for(int i=0;i*k<n;i++)
	{
		for(int j=n-i*(k-1)+1;i!=0&&j<=n-(i-1)*(k-1);j++)
		{
			sum+=min(a[j]-1,d);
		}
		long long pr=0;
		if(lc>lm)
		{
			long long tempsum=sum+pro_sumc[i]+pro_summ[n-(k-1)*i]-pro_summ[i];
			long long tempneed=need_sumc[i]+need_summ[n-(k-1)*i]-need_summ[i];
			if(tempsum>=tempneed)
			{
				pr=i*pc+(n-i*k)*pm+(tempneed)*t;
				ans=min(ans,pr);
			}
		}
		else
		{	
			long long tempsum=sum+pro_summ[n-k*i]+pro_sumc[n-(k-1)*i]-pro_sumc[n-k*i];
			long long tempneed=need_summ[n-k*i]+need_sumc[n-(k-1)*i]-need_sumc[n-k*i];
			if(tempsum>=tempneed)
			{
				pr=i*pc+(n-i*k)*pm+(tempneed)*t;
				ans=min(ans,pr);
			}
		}
		
	}
	int num=(n%k==0?n/k:n/k+1);
	long long tempsum=0;
	//printf("%d??
",num);
	for(int i=num+1;i<=n;i++)
		tempsum+=min(a[i]-1,d);
	//printf("???%d %d
",need_sumc[num],pro_sumc[num]+tempsum);
	if(pro_sumc[num]+tempsum>=need_sumc[num])
		ans=min(ans,need_sumc[num]*t+pc*num);
	
	if(ans==inf)
		printf("-1
");
	else
		printf("%lld
",ans);
	return 0;
}
/*
2 2
18 1000 16 1
5 3
16 15

2 2
23 10 15 5
2 2
9 20

2 2
15 10 23 5
2 2
9 20

*/
原文地址:https://www.cnblogs.com/cherrypill/p/14071439.html