[JSOI2011]柠檬

news/2024/7/3 17:45:53

https://www.zybuluo.com/ysner/note/1236327

题面

给定一段长度为\(n\)的序列\(a\),需要把它分为任意多段。
对于每一段,需要选出一个数\(p\),若\(p\)在该段中出现\(k\)次,则该段贡献为\(pk^2\)
最大化贡献和。

  • \(n\leq10^6,x\leq10^5\)

    解析

    orz GXZlegend
    显然有个性质:每一段的两端同为\(x\)
    因为两端多出的数不可能对该段有贡献,提出它们以期望对其他段产生贡献,才能实现贡献最大化。

则可设状态为\(f_i\)表示前\(i\)个数产生的最大贡献,\(S_i\)表示在第\(i\)个位置这个数是第几次出现(出现次数的前缀和)。
有方程式\[f_i=max\{f_{j-1}+a_i*(S_i-S_j+1)^2\}(j<i,a_j=a_i)\]
看起来\(O(n^2)\)很虚啊。
这时就要考虑斜率优化了。

原式为\[f_i=f_{j-1}+a_i*(S_i-S_j+1)^2\]
于是“参变量分离”,与\(j\)有关的项放到\(y,x\)项,无关的放到\(k,b\)项。
于是化为\[f_i=f_{j-1}+a_i*(S_i^2+(S_j-1)^2-2*S_i*(S_j-1)\]
\[f_{i-1}+a_i(S_j-1)^2=2*a_iS_i*(S_j-1)-a_iS_i^2+f_i\]
其中\(k=2S_i,y=f_{i-1}+a_i(S_j-1)^2,x=a_i(S_j-1),k=a_iS_i,b=f_i-a_iS_i^2\)
我们可以维护一个单调栈,栈顶维护最优决策。

  • 栈顶\(k\)比因新加入元素而产生的\(k\)小,就弹栈。
  • 新加入元素,进栈。
  • 栈顶\(k\)小于\(2S_i\),就弹栈。
  • 取栈顶运算
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e5+100;
ll n,c[N],s[N],num[N],x[N],y[N],dp[N];
vector<int>Q[N/10];
il ll gi()
{
   re ll x=0,t=1;
   re char ch=getchar();
   while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
   if(ch=='-') t=-1,ch=getchar();
   while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
   return x*t;
}
il double slope(re int a,re int b){ return ((double)(y[a]-y[b]))/(x[a]-x[b]);}
int main()
{
  n=gi();
  fp(i,1,n) c[i]=gi(),s[i]=++num[c[i]];
  fp(i,1,n)
    {
      re int col=c[i],top=Q[col].size()-1;
      x[i]=(s[i]-1)*col;y[i]=x[i]*(s[i]-1)+dp[i-1];
      while(top>0&&slope(Q[col][top-1],Q[col][top])<slope(Q[col][top],i)) Q[col].pop_back(),--top;
      Q[col].push_back(i);++top;
      while(top>0&&slope(Q[col][top-1],Q[col][top])<2*s[i]) Q[col].pop_back(),--top;
      re int t=Q[col][top];
      dp[i]=dp[t-1]+col*(s[i]-s[t]+1)*(s[i]-s[t]+1);
    }
  printf("%lld\n",dp[n]);
  return 0;
}

转载于:https://www.cnblogs.com/yanshannan/p/9409400.html


http://www.niftyadmin.cn/n/4557461.html

相关文章

异构数据库同步数据(mysql2sqlserver)

需要使用datax插件&#xff0c;是阿里开源插件&#xff0c;能够实现各种异构数据库的数据同步 github地址datax 找到下面的快速开始&#xff0c;点击Quick Start就可以下载插件 转载&#xff1a;详细介绍 如果想实现增量同步&#xff0c;就需要使用where和数据库中的时间字段…

参考文献引用网页怎么标注 ?

【格式】 [序号]主要责任者.电子文献题名.电子文献出处[电子文献及载体类型标识].或可获得地址&#xff0c;发表或更新日期/引用日期. 维基百科:引用维基百科 【举例】 [16] 王明亮.关于中国学术期刊标准化数据库系统工程的进展[EB/OL].http: //www.cajcd.edu.cn/pub/wml.txt/9…

Java 8 (7) 重构、测试和调试

为改善可读性和灵活性重构代码 看到这里我们已经可以使用lambda和stream API来使代码更简洁&#xff0c;用在新项目上。但大多数并不是全新的项目&#xff0c;而是对现有代码的重构&#xff0c;让它变的更简洁可读&#xff0c;更灵活。 改善代码的可读性 别人理解这段代码的难易…

java深入虚拟机

今天是个好日子&#xff0c;测试数据在哪里今天是个好日子&#xff0c;测试数据在哪里今天是个好日子&#xff0c;测试数据在哪里今天是个好日子&#xff0c;测试数据在哪里今天是个好日子&#xff0c;测试数据在哪里今天是个好日子&#xff0c;测试数据在哪里今天是个好日子&a…

开源工程系列之2.5寸硬盘盒

手上攒了几个硬盘&#xff0c;有2.5寸的&#xff0c;也有3.5寸的。我打算把资料整理一下&#xff0c;放到一个盘子里&#xff0c;但是懒得拆电脑装硬盘。曾经看到过一种叫做易驱线的东西&#xff0c;一头可以插到2.5寸或3.5寸的硬盘上&#xff0c;而另外一头则是USB。这真是个好…

这个程序哪里错了

getch();要写成_getch(); ||| 程序没有问题scanf("a%d b20 这个程序也没错 &c); &b &a &c);更改为scanf("%d%d%d" &b &a c%d" b%d c1回车 ||| scanf("a%d b2 &c);输入数的时候注意下就行了输入&#xff1a;a3 &b &am…

MUI的踩坑笔记

最近在做公司项目的手机端实现&#xff0c;稍微记录下遇到的坑 1、在app开发中&#xff0c;若要使用HTML5扩展api&#xff0c;必须等plusready事件发生后才能正常使用&#xff0c;mui将该事件封装成了mui.plusReady()方法&#xff0c;涉及到HTML5的api&#xff0c;建议都写在mu…

1.html前端多选框的全选与全不选

1.这是checkbox&#xff1a; <td><input type"checkbox" id"checkAll" onclick"checkBox()" /></td><td><input type"checkbox" name"ids" /></td> <td><input type"ch…