洛谷P6674 [CCO2019] Card Scoring

考虑 DP,设 fi 为考虑了前 i 张牌的最大总分,ai 为第 i 张牌的种类,si 为前 i 张牌和第 i 张牌的种类相同的牌的个数,得转移为:

fi=maxaj=ai{fj1+(sisj+1)12k}

直接转移是 O(n2) 的,需要考虑优化。发现对于种类相同的牌之间的转移具有决策单调性,即转移 j,k,其中 j<k,若转移 j 比转移 k 更优,会一直比其优,原因是转移的第二项关于 si 的导数恒为正值。

对于每种牌维护一个单调栈,每次插入时二分相邻项中前一项代替后一项的时间即可更新单调栈。

#include<bits/stdc++.h> #define maxn 1000010 #define siz(x) (ve[x].size()) #define ve(x,y) (ve[x][ve[x].size()-y]) using namespace std; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int k,n; int a[maxn],cnt[maxn],s[maxn]; double v[maxn],f[maxn]; vector<int> ve[maxn]; double calc(int x,int sum) { return f[x-1]+v[sum]; } int get(int i,int j) { int l=1,r=n,pos=n+1; while(l<=r) { int mid=(l+r)>>1; if(calc(i,mid-s[i]+1)>=calc(j,mid-s[j]+1)) pos=mid,r=mid-1; else l=mid+1; } return pos; } int main() { read(k),read(n); for(int i=1;i<=n;++i) { double t=1; for(int j=1;j<=k;++j) t*=i; v[i]=sqrt(t),read(a[i]),s[i]=++cnt[a[i]]; } for(int i=1;i<=n;++i) { int x=a[i]; while(siz(x)>1&&get(ve(x,2),ve(x,1))<=get(ve(x,1),i)) ve[x].pop_back(); ve[x].push_back(i); while(siz(x)>1&&get(ve(x,2),ve(x,1))<=s[i]) ve[x].pop_back(); f[i]=calc(ve(x,1),s[i]-s[ve(x,1)]+1); } printf("%.10lf",f[n]); return 0; }

__EOF__

本文作者lhm_
本文链接https://www.cnblogs.com/lhm-/p/14253409.html
关于博主:sjzez 的一名 OI 学生
版权声明:转载标明出处
声援博主:希望得到宝贵的建议
posted @   lhm_liu  阅读(181)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示