…?
这是同份代码。
题目描述
一些样例
#1
输入
4 1
1 2
2 3
1 2
3 8
3 2 1 3
输出
21
#2
输入
8 3
1 2
2 5
3 2
2 3
1 4
1 6
2 2
3 3
1 3 2 1 4 5 2 1
输出
57
#3
输入
10 3
9 9
8 8
5 7
6 6
5 5
5 5
3 3
2 2
1 1
9 9
1 2 3 5 5 5 6 7 8 9
输出
124
思路
100%数据:n<=5×104,m<=500,0<pi<=104,0<ki<=109,0<xi<=109
ki很大要用离散化。(话说我这离散怎么那么奇怪)
然后用前缀和和前缀最大值预处理下。
dp方程就按着题目所述瞎写:设i为层数,j为施法次数
f[i][j] = max(f[i][j], f[i-1][j]+cz1[X[i]]);
//第一种操作,加上已经预处理的所有X[i]类型的值
f[i][j] = max(f[i][j], f[i-1][j]+maxx[i]);
//第二种操作,加上已经预处理的经过的保护层的最大值
f[i][j] = max(f[i][j], f[i-2][j-1]+max(cz1[X[i]],maxx[i])*2);
//第三种操作,i-2是因为i-1的地方因为要施法所以不能取值
代码
又变丑了()
#include<cstdio>
#include<algorith>
using namespace std;
int n,m,cnt,maxans,im3,l[10001],k[50001],p[50001],X[50001],maxx[50001],cz1[50001],f[5][50001];
int read(){ //快读
int x=0;
char c;
while(c>'9'||c<'0') c = getchar();
while(c<='9'&&c>='0'){
x = x*10+c-48;
c = getchar();
}
return x;
}
int findd(int d) //离散
{
int ll=cnt, rr=1, mid;
while(rr<=ll)
{
mid=(ll+rr)/2;
if(d>l[mid]) rr=mid+1;
if(d<l[mid]) ll=mid-1;
if(d==l[mid]) return mid;
}
}
void inn(){ //输入与预处理
n = read(); m = read(); //输入
for(int i=1; i<=n; ++i)
{
k[i]=read(); p[i]=read();
l[++cnt] = k[i]; //离散
maxx[i] = max(maxx[i-1],p[i]);//前缀最大值
}
for(int i=1; i<=n; ++i)
{
X[i] = read();
l[++cnt] = X[i];
}
sort(l+1,l+1+cnt); //离散
cnt=unique(l+1,l+cnt+1)-l-1;
for(int i=1; i<=n; ++i) //离散
{
X[i] = findd(X[i]);
k[i] = findd(k[i]);
}
}
void workk(){
for(int i=1; i<=n; ++i) //层数
{
cz1[k[i]] += p[i]; //求所有魔法种类为k[i]的值的和
im3 = i%3; //滚动数组
for(int j=0; j<=m; ++j) //施法次数
{
f[im3][j] = max(f[im3][j], f[(i-1)%3][j]+cz1[X[i]]); //如上所述
f[im3][j] = max(f[im3][j], f[(i-1)%3][j]+maxx[i]);
if(j*2>i||i==1) break; //注意边界(这里写得好乱)
if(j>0) f[im3][j] = max(f[imm3][j], f[(i-2)%3][j-1]+max(cz1[X[i]],maxx[i])*2);
maxans = max(maxans,f[im3][j]); //记录结果(这应该放到dp结束后的)
}
}
}
int main()
{
inn();
workk();
printf("%d",maxans);
}