题目

  点这里看题目。

分析

  先特判掉\(K=2\)的情况。

  首先可以考虑到一个简单 DP :

  \(f(i)\):前\(i\)张牌的最大贡献。

  转移可以\(O(n^2)\)地枚举区间众数,但它不存在决策单调性,众数查询也很难优化。

  考虑另一种转移。我们对于\(f(i)\),只取它结尾的点数的后缀

\[f(i)=\max_{1\le j\le i,a_j=a_i}\{f(j-1)+s(i)-s(j)+1\}
\]

  其中的\(s_i\)为前\(i\)张牌里与第\(i\)张点数相同的牌的张数。

  这个转移从全局来看也不存在单调性,但实际上,它具有部分单调性

  对于所有的结尾点数相同的\(f\),除开\(i=j\)的转移,剩下的转移中它的最优决策点与前面的结尾点数相同的\(f\)的已有决策点是单调不增的

  利用好这个性质,我们就可以对于每个颜色维护一个\(i\not=j\)的转移的单调栈,计算新的值的时候把已有的不优的决策点弹掉,插入新的值的时候二分一下右边界,时间是\(O(n\log_2n)\)。

代码

#include <cmath>
#include <cstdio>
#include <vector>
using namespace std; const int MAXN = 1e6 + 5; template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
} template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
} template<typename _T>
_T MAX( const _T a, const _T b )
{
return a > b ? a : b;
} vector<int> pos[MAXN]; double pw[MAXN], f[MAXN];
int stk[MAXN], but[MAXN], top[MAXN], rig[MAXN];
int A[MAXN], pre[MAXN], tot[MAXN], vised[MAXN];
int N, K; double getDP( const int i, const int j )
{
return f[j - 1] + pw[pre[i] - pre[j] + 1];
} int get( const int i, const int j )
{
int id = A[i];
int l = vised[id] - 1, r = pos[id].size() - 1, mid;
while( r - l > 1 )
{
mid = l + r >> 1;
if( getDP( pos[id][mid], i ) >= getDP( pos[id][mid], j ) ) l = mid;
else r = mid - 1;
}
if( getDP( pos[id][r], i ) >= getDP( pos[id][r], j ) ) return pos[id][r];
return pos[id][l];
} int main()
{
read( K ), read( N );
for( int i = 1 ; i <= N ; i ++ ) pw[i] = pow( i, 1.0 * K / 2 );
for( int i = 1 ; i <= N ; i ++ ) read( A[i] ), pre[i] = ++ tot[A[i]], pos[A[i]].push_back( i );
if( K == 2 ) { printf( "%.10lf\n", ( double ) N ); return 0; }
int siz = 0;
for( int i = 1 ; i <= N ; i ++ )
if( tot[i] )
but[i] = siz + 1, top[i] = siz, siz += tot[i];
int id;
for( int i = 1 ; i <= N ; i ++ )
{
f[i] = f[i - 1] + 1, id = A[i];
while( but[id] < top[id] && i > rig[top[id] - 1] ) top[id] --;
if( but[id] <= top[id] ) f[i] = MAX( f[i], getDP( i, stk[top[id]] ) );
while( but[id] < top[id] && get( i, stk[top[id]] ) >= rig[top[id] - 1] ) top[id] --;
if( but[id] <= top[id] ) rig[top[id]] = get( i, stk[top[id]] );
stk[++ top[id]] = i, rig[top[id]] = N;
vised[id] ++;
}
printf( "%.10lf\n", f[N] );
return 0;
}

最新文章

  1. create dll project based on the existing project
  2. AC算法 及python实现
  3. 为开发者准备的9个实用PHP代码片段
  4. 光流算法:灰度恒常约束,LK算法,HS算法
  5. poj 2593 Max Sequence(线性dp)
  6. CodeForces 700B Connecting Universities
  7. (转)JAVA堆栈操作
  8. CentOS 使用firewalld打开防火墙与端口
  9. pip3 install的时候报错timed out
  10. MySql.Data.MySqlClient.MySqlException (0x80004005): Unable to connect to any of the specified MySQL hosts.
  11. python 全栈开发,Day129(玩具开机提示语,为多个玩具发送点播,聊天界面,app录音,app与服务器端文件传输,简单的对话)
  12. maven library has broken path和pom jar包导入失败
  13. BZOJ.1143.[CTSC2008]祭祀(Dilworth定理 最大流ISAP)
  14. 使用sessionStorage解决vuex在页面刷新后数据被清除的问题
  15. 【数据结构】循环队列 C语言实现
  16. 动态规划-Predict the Winner
  17. HMM的概述(五个基本元素、两个假设、三个解决的问题)
  18. linux内核第一二章总结
  19. Android代码混淆及项目发布方法记录
  20. 怎样利用JDBC启动Oracle 自己主动追踪(auto trace)

热门文章

  1. Objective-C中的加号与减号
  2. Gym101635C Macarons
  3. pyenv,轻松切换各种python版本
  4. Cube-UI组件中create-api 模块的基本使用
  5. 加密通信软件Signal 2.92版本编译安装折腾手记(Ubuntu 18.04)
  6. ajax 请求PHP返回json格式的处理
  7. idea打印中文乱码
  8. 分布式项目开发-springmvc.xmll基础配置
  9. ATT&amp;CK红队评估实战靶场(一)
  10. dell5460笔记本电脑ubuntu18.04系统音频驱动的安装和使用