吐槽:这题目起的好随便啊
原题
小明在业余时间喜欢打电子游戏,不是星际和魔兽这些,是赛尔号一类的游戏。最近小明在玩一款新出的游戏,叫做■■■■■■■■。小明觉得游戏里自己的装备太垃圾了,每次都被大神虐,一怒之下充了■■元准备强化装备。
这个游戏中用于强化装备的道具叫做强化符文。有以下3 种:
- 赋值强化符文,对某个装备使用这个符文以后,装备威力值会变为一个常数。因为这个功能很IMBA,可以让一个垃圾装备变得非常牛■,所以它在游戏里很稀有,市场上最多能见到一个。
- 加法强化符文,对某个装备使用后,威力值加上一个常数。
- 乘法强化符文,对某个装备使用后,威力值乘上一个常数。
市场上有M 个不同强化符文可以购买,小明有N 件装备准备强化,他只能购买K 个强化符文,然后以任意顺序使用这些符文,强化他的任意装备(一个装备可以不强化也可以强化多次)。根据游戏的设定,所有装备威力值乘积为总效果。请为他设计一个购买和强化方案,使强化后的所有装备总效果值最大。
由于小明RP 不太好,打BOSS 都不掉神装,所以他的装备不超过两件。
题目大意(有改动) |
---|
给你一个含N个元素的序列 ( N ⩽ 2 ) (N\leqslant2) (N⩽2),有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。
几个显然的事实
- 看看数据范围, n ⩽ 2 n\leqslant 2 n⩽2,不用想,这肯定是题目的切入点 。
- a ( b x + c ) > a b ( x + c ) a(bx+c) >ab(x+c) a(bx+c)>ab(x+c)所以加法应该优先于乘法使用,赋值优于加法
- 加、乘法都好,无论怎么分配,选权值大的就是王道
我一开始,以为答案是加起来,就无从下手。
后来,我才发现总威力是乘积。
那就很好办了。。。
首先,乘法无论作用于第一个还是第二个,效果是一样的。所以,乘法的问题可以单独解决。
其次,这题显然用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(n2∑ci)
凉定了?????
NO
- 加、乘法都好,无论怎么分配,选权值大的就是王道
按
t
y
p
e
type
type为第一关键字
c
c
c为第二关键字排序以后,不论选了几个,肯定都集中在前面。
时间复杂度降至
O
(
n
∑
c
i
)
O(n\sum c_i)
O(n∑ci)
结果
爆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;
}