题意

给定一个长度为n的序列,你可以进行若干次操作:

选择一个区间,删掉,并获得Val[Len]的得分,Len为这个区间的长度:

其中这个区间满足:

1.相邻两个数差的绝对值为1

2.每个数都大于相邻两个数的平均数

问最大得分。

解法

一眼过去,得到一个可能是O(n^4)的做法。

设f[i][j]表示删除掉[i,j]这个区间的最大得分。

然后发现只有这个转移不了,然后又多设了一个g[i][j][0/1],表示以a[i]开头的,以a[j]结尾的上升或下降的最大得分。

然后发现这个好像要多存一个个数,然后很倦生,然后就弃疗了。

赛后发现,其实标算跟我的做法差不多,多存一维个数可以用上升序列的性质直接算。

然后打着打着又发现了一个问题。

f[i][j]<-g[i][k]+g[k][j]的合并有点奇怪。

然后水过了之后再看标,恍然大悟。

靠这样转移就可以把两个g拼接起来了。

Code

#include<bits/stdc++.h>
#define ll long long
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define fd(i,x,y) for(int i=x;i>=y;i--)
using namespace std; const int maxn=407,Inf=0x7fffffff; int n,Val[maxn],a[maxn];
int Up[maxn][maxn],Dn[maxn][maxn]; void getUpDn(){
fo(i,1,n){
Up[i][i]=0;
fo(j,i+1,n){
if (Up[i][j-1]) Up[i][j]=Up[i][j-1];
else if (a[j]==a[j-1]+1) Up[i][j]=0;
else Up[i][j]=j;
}
}
fo(i,1,n){
Dn[i][i]=0;
fo(j,i+1,n){
if (Dn[i][j-1]) Dn[i][j]=Dn[i][j-1];
else if (a[j]==a[j-1]-1) Dn[i][j]=0;
else Dn[i][j]=j;
}
}
}
void Init(){
scanf("%d",&n);
fo(i,1,n) scanf("%d",&Val[i]);
fo(i,1,n) scanf("%d",&a[i]);
getUpDn();
} int Check(int l,int r,int L=0,int R=0){
if (L){
if (r-l+1==0) return Check(L,R);
else if (R-L+1==0) return Check(l,r);
else{
int x=Up[l][r];
if (x==0){
if (a[r]+1==a[L]) return Check(L,R);
else if (a[r]-1==a[L]) return (Dn[L][R]==0)*2;
else return 0;
}else{
if (Dn[x-1][r]==0 && a[r]-1==a[L]) return (Dn[L][R]==0)*2;
else return 0;
}
}
}else{
if (l==r) return 1;
else{
int x=Up[l][r];
if (x==0) return 1;
else return (Dn[x-1][r]==0)*2;
}
}
}
int f[maxn][maxn],g[maxn],h[maxn][maxn][2],Ans=0;
void getF(){
fo(Len,2,n)
fo(i,1,n){
int j=i+Len-1;
if (j>n) break;
fo(k,i,j-1){
if (a[k]+1==a[j]) h[i][j][0]=max(h[i][j][0],h[i][k][0]+f[k+1][j-1]);
if (a[k]-1==a[j]) h[i][j][1]=max(h[i][j][1],h[i][k][1]+f[k+1][j-1]);
}
fo(k,i,j-1){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
}
fo(k,i,j-1)
if (h[i][k][0]>-1e8 && h[k][j][1]>-1e8)
f[i][j]=max(f[i][j],h[i][k][0]+h[k][j][1]+Val[a[k]-a[i]+a[k]-a[j]+1]);
if (h[i][j][0]>-1e8) f[i][j]=max(f[i][j],h[i][j][0]+Val[a[j]-a[i]+1]);
if (h[i][j][1]>-1e8) f[i][j]=max(f[i][j],h[i][j][1]+Val[a[i]-a[j]+1]);
}
}
void getG(){
g[0]=0;
fo(i,1,n){
g[i]=g[i-1];
fo(j,0,i-1){
g[i]=max(g[i],g[j]+f[j+1][i]);
}
}
}
void Solve(){
fo(i,1,n) fo(j,1,n) f[i][j]=h[i][j][0]=h[i][j][1]=-1e9;
fo(i,1,n){
f[i][i-1]=0;
fo(j,i,n){
if (Check(i,j)) f[i][j]=Val[j-i+1];
else f[i][j]=-1e9;
if (j>i) h[i][j][0]=h[i][j][1]=-1e9;
else h[i][j][0]=h[i][j][1]=0;
}
}
getF();
getG();
Ans=g[n];
} void Print(){
printf("%d\n",Ans);
} int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
Init();
Solve();
Print();
return 0;
}

最新文章

  1. linux查看系统命令
  2. 用Action的属性接受参数
  3. 转载:关于Matlab GUI的一些经验总结
  4. winform INI文件操作辅助类
  5. 【实习记】2014-08-18使用curl排错http头的content-length
  6. Android 读取手机某个文件夹目录及子文件夹中所有的txt文件
  7. phpcms 调用全站最新发布数据
  8. linux: /usr/bin/ld: cannot find -lloc
  9. MyBatis-plus 代码自动生成器
  10. java多线程面试总结
  11. Akka(13): 分布式运算:Cluster-Sharding-运算的集群分片
  12. html5 textarea 文本框根据输入内容自适应高度
  13. spark2.2 DataFrame的一些算子操作
  14. 把玩爬虫框架Gecco
  15. 《并行程序设计导论》——MPI(Microsoft MPI)(1):Hello
  16. CCF系列之相邻数对(201409-1)
  17. ionic2+Angular 使用HttpInterceptorService拦截器 统一处理数据请求
  18. docker(五) 使用Docker Registry搭建镜像私服
  19. matlab的Deep Learning的toolbox 中的SAE算法
  20. 使用FFmpeg如何转发一个RTSP视频流

热门文章

  1. C# .net async await 学习
  2. ajax跨域请求使用代理
  3. Java基础:基本类型
  4. Java并发编程中的若干核心技术,向高手进阶!
  5. 19.SimLogin_case04
  6. 侧滑关闭Activity的解决方案——SwipeBackLayout
  7. Neo4j-Apoc
  8. CentOS7-Minimal安装MySQL服务
  9. nginx 配置文件备份 nginx.conf and vhosts
  10. [Ceoi2016|BZOJ4936] Match