您的位置:首页 > 其它

【DP】LibreOJ NOI Round #1[A.接竹竿]题解

2017-07-07 14:50 246 查看

题目概述

有n张牌,每张牌有一种花色c和一个权值v。如果两张牌花色相同就可以把两张牌间的牌都拿光(包括这两张)并得到所有牌的权值加和。求最大权值。

解题报告

一看就是线性DP啊,定义f[i]表示前i个的最优解,那么转移方程就是f[i]=max{f[j-1]-sum[j-1]+sum[i]|c[i]=c[j]}。然后我们发现f[j-1]-sum[j-1]只和j有关,与i无关,所以我们只需要记录MAX[i]表示颜色i目前的max{f[j-1]-sum[j-1]},每次更新就行了。

但是考试的时候我一看,哇NOI难度的第一题(汗)我竟然能水60分,于是暴力做了之后就没去管了,结果之后发现水上天了,下次再也不能这样了T_T。

示例程序

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000000,maxk=1000000;

int n,K,col[maxk+5];
LL sum[maxn+5],f[maxn+5],MAX[maxk+5];

bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
x=tot*f;
return Eoln(ch);
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);readi(K);
for (int i=1;i<=n;i++) readi(col[i]);
for (int i=1,x;i<=n;i++) readi(x),sum[i]=sum[i-1]+x;
memset(MAX,192,sizeof(MAX));
for (int i=1;i<=n;i++)
{
f[i]=max(f[i-1],MAX[col[i]]+sum[i]);
MAX[col[i]]=max(MAX[col[i]],f[i-1]-sum[i-1]);
}
return printf("%lld\n",f
),0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: