JZOJ 4245【五校联考6day2】er

4 篇文章 0 订阅

吐槽:这题目起的好随便啊

原题

小明在业余时间喜欢打电子游戏,不是星际和魔兽这些,是赛尔号一类的游戏。最近小明在玩一款新出的游戏,叫做■■■■■■■■。小明觉得游戏里自己的装备太垃圾了,每次都被大神虐,一怒之下充了■■元准备强化装备。
这个游戏中用于强化装备的道具叫做强化符文。有以下3 种:

  1. 赋值强化符文,对某个装备使用这个符文以后,装备威力值会变为一个常数。因为这个功能很IMBA,可以让一个垃圾装备变得非常牛■,所以它在游戏里很稀有,市场上最多能见到一个。
  2. 加法强化符文,对某个装备使用后,威力值加上一个常数。
  3. 乘法强化符文,对某个装备使用后,威力值乘上一个常数。
    市场上有M 个不同强化符文可以购买,小明有N 件装备准备强化,他只能购买K 个强化符文,然后以任意顺序使用这些符文,强化他的任意装备(一个装备可以不强化也可以强化多次)。根据游戏的设定,所有装备威力值乘积为总效果。请为他设计一个购买和强化方案,使强化后的所有装备总效果值最大。
    由于小明RP 不太好,打BOSS 都不掉神装,所以他的装备不超过两件。
题目大意(有改动)
给你一个含N个元素的序列 ( N ⩽ 2 ) (N\leqslant2) (N2),有m个修改操作,每个操作有两个参数:type,c。
当type=1时,表示把某元素赋为c
当type=2时,表示把某元素加上c
当type=3时,表示把某元素乘上c
求使用k个不同操作可以获得的序列元素乘积的最大值,值可能很大,请输出 ln ⁡ ( a n s ) \ln(ans) ln(ans)

Input

第一行3 个正整数N;M;K, 含义见题面。
第二行N 个正整数Ai,表示他的每个装备的初始威力值。
第三行开始共M 行,每行两个正整数Type_i;Ci,描述一个强化符文。Type_i表示符文类型,1 表示赋值,2 表示加法,3 表示乘法。Ci 是对应的常数值。

Output

一个数,表示最大的总效果值。由于这个数可能很大,请输出它的自然对数,保留3 位小数。

Sample Input

2 5 3
0 1
2 3
2 1
2 4
3 2

Sample Output

4.159

Data Constraint

对于20% 的数据,N = 1;
对于全部数据M,K ≤ 100;N ≤ 2,最多一个Type_i = 1。
输入数据中所有数不超过2000。

几个显然的事实

  1. 看看数据范围, n ⩽ 2 n\leqslant 2 n2,不用想,这肯定是题目的切入点 。
  2. a ( b x + c ) > a b ( x + c ) a(bx+c) >ab(x+c) a(bx+c)>ab(x+c)所以加法应该优先于乘法使用,赋值优于加法
  3. 加、乘法都好,无论怎么分配,选权值大的就是王道

我一开始,以为答案是加起来,就无从下手。
后来,我才发现总威力是乘积。
那就很好办了。。。

首先,乘法无论作用于第一个还是第二个,效果是一样的。所以,乘法的问题可以单独解决。
其次,这题显然用DP,加法部分的结果含有乘法,不好处理,考虑到数据范围

输入数据中所有数不超过2000。

A i + ∑ t y p e i = 2 c i A_i+\sum_{type_{i}=2} c_{i} Ai+typei=2ci不会超过 2000 × 100 = 200000 2000\times 100=200000 2000×100=200000
如果设 f i , j f_{i,j} fi,j表示选了 i i i个, A 1 = j A_1=j A1=j, A 2 A_2 A2的最大值。
不仅空间复杂度可行,也顺便解决了乘法难转移的问题。
只是时间复杂度。。。。
O ( n 2 ∑ c i ) O(n^2\sum c_i) O(n2ci)

凉定了?????

NO

  1. 加、乘法都好,无论怎么分配,选权值大的就是王道

t y p e type type为第一关键字 c c c为第二关键字排序以后,不论选了几个,肯定都集中在前面。
时间复杂度降至 O ( n ∑ c i ) O(n\sum c_i) O(nci)

结果

爆0。。。
至于原因。。。
爆零部分代码:

		while(type[i]<mt||(type[i]==mt&&c[i]>mc)) i++;
		while(type[j]>mt||(type[j]==mt&&c[i]<mt)) j--;
		//                                ^  ^^不爆0才怪

最终:

#include<cstdio>
#include<cstring>
#include<math.h>
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
#define ln(x) (log(x))
using namespace std;
int A[4];
int type[110],c[300];
long long f[110][200010];
double maxf[110];
void qsort(int l,int r)
{
	int i=l,j=r,mt=type[(l+r)/2],mc=c[(l+r)/2],t;
	while(i<=j)
	{
		while(type[i]<mt||(type[i]==mt&&c[i]>mc)) i++;
		while(type[j]>mt||(type[j]==mt&&c[j]<mc)) j--;
		if(i<=j)
		{
			t=type[i];type[i]=type[j];type[j]=t;
			t=c[i];c[i]=c[j];c[j]=t;
			i++;j--;
		}
	}
	if(i<r) qsort(i,r);
	if(l<j) qsort(l,j);
}
int main()
{
	//freopen("er.in","r",stdin);
	//freopen("er.out","w",stdout);
	int n,m,k,i,j,sta;double nans=0;
	scanf("%d%d%d",&n,&m,&k);
	A[2]=1;
	for(i=1;i<=n;i++) scanf("%d",&A[i]);
	for(i=1;i<=m;i++) scanf("%d%d",&type[i],&c[i]);
	qsort(1,m);
	memset(f,-1,sizeof(f));
	maxf[0]=ln(A[2]*A[1]);f[0][A[1]]=A[2];
	for(i=1;i<=k;i++)
	{
		if(type[i]>2) break;
		if(type[i]==1) for(j=0;j<=c[i];j++) f[i][c[i]]=max(f[i][c[i]],f[i-1][j]);
		for(j=0;j<=200000;j++)
		{
			if(type[i]==1&&f[i-1][j]>=0&&n==2) f[i][j]=max(f[i][j],c[i]);
			if(type[i]==2)
			{
				if(j>=c[i]) f[i][j]=max(f[i-1][j-c[i]],f[i][j]);
				if(f[i-1][j]>=0&&n==2) f[i][j]=max(f[i][j],f[i-1][j]+c[i]);
	 		//	printf("%d %d %d\n",i,j,f[i][j]);
			}
		}
		maxf[i]=-1000000.0;
		for(j=0;j<=200000;j++)
			if(ln(f[i][j]*j)>maxf[i]) maxf[i]=ln(f[i][j]*j);
	}
	for(sta=1;sta<=m;sta++)
		if(type[sta]>2) break;
	double sum=0,ans=0;
	for(i=m+1;i<=2*m;i++) c[i]=1;
	for(i=sta;i-sta<=k;i++)
	{
		if(i-sta>k) break;
		nans=-10000000;
		for(j=0;j<=k-(i-sta);j++)
		{
			nans=max(nans,maxf[j]);
		}
		if(ans<nans+sum)ans=nans+sum;
		sum=sum+ln(c[i]);
	}
	printf("%.3lf\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值