[bzoj1584]打扫卫生
来源:互联网 发布:java源代码阅读工具 编辑:程序博客网 时间:2024/04/29 09:57
题目大意
把一个长度为n的序列分成若干段。
每一段的代价为其中不同的数的个数的平方。
最小化代价。
DP
设f[i]表示把[1..i]分成若干段的最优解。
那么显然有一个单调性f[i]<=f[i+1]。
我们可以枚举最后一段中不同的数的个数j。那么设b[j]表示最小的k满足[k,i]之间恰好有j个不同的数。
那么显然
然而这样不行呀。
我们发现,每个数单独一段可以得到答案为n的一个解。
那么也就是说,如果一段中有超过根号n种数字,这绝对不是最优。
因此j的枚举上限可以对根号n取min。
接下来设next[i]表示最大的
next数组很好算,只需要一个桶last表示每种数的最后出现位置即可。
那么i每右移一位,b数组如何更新呢?
假若
否则,我们需要不断把b[j]往后移,直至[b[j],i-1]恰好有j-1个不同数。
也就是找到一个最小的k>=b[j]满足last[a[k]]=k(即其是最后一个),那么b[j]=k+1。
这样来调整b数组的话b数组每一位都单调增,一共根号位,所以总复杂度n*根号n。
然后每次f的转移是根号的,总复杂度也为n*根号n。
#include<cstdio>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=40000+10,maxc=200+10;int next[maxn],f[maxn],a[maxn],b[maxc],last[maxn],s[maxn];int i,j,k,l,t,n,m,c,top;int main(){ freopen("1584.in","r",stdin);freopen("1584.out","w",stdout); scanf("%d%d",&n,&m); fo(i,1,n) scanf("%d",&a[i]); c=floor(sqrt(n)); fo(i,1,c) b[i]=1; fo(i,1,n){ next[i]=last[a[i]]; last[a[i]]=i; fo(j,1,min(top,c)){ if (b[j]>next[i]){ while (1){ b[j]++; if (b[j]-1==last[a[b[j]-1]]) break; } } } if (!next[i]) top++; f[i]=i; fo(j,1,min(top,c)) f[i]=min(f[i],f[b[j]-1]+j*j); } printf("%d\n",f[n]);}
0 0
- [bzoj1584]打扫卫生
- bzoj1584【Usaco2009 Mar】Cleaning Up 打扫卫生
- [bzoj1584] [Usaco2009 Mar]Cleaning Up 打扫卫生
- 【BZOJ1584】[Usaco2009 Mar]Cleaning Up 打扫卫生【DP】
- bzoj1584 [Usaco2009 Mar]Cleaning Up 打扫卫生 dp
- [BZOJ1584][Usaco2009 Mar]Cleaning Up 打扫卫生(dp+数学相关优化)
- 哪里有打扫卫生
- 今天在家打扫卫生了
- DP Cleaning Up 打扫卫生
- 如何计算自己哪天打扫卫生
- 先打扫卫生,然后在写规划
- 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生
- bzoj 1584 Cleaning Up 打扫卫生 dp
- bzoj1584
- 关于宿舍卫生打扫分配工作的程序
- BZOJ 1584 [Usaco2009 Mar]Cleaning Up 打扫卫生 动态规划
- 打扫打扫打扫
- 打扫打扫,重整旗鼓
- 12球称重问题
- Sudoku
- 盲人摸扑克
- 从头学android_短信发送器
- 动态代理的简单实现
- [bzoj1584]打扫卫生
- 史上最全的Android ViewDragHelper解析
- 从二叉树的前序和中序得到后续遍历算法
- VLC架构剖析
- Storyboard学习四(Label)
- easyx
- ListView item点击事件问题:第一次点击有效,再次点击item无效。场景是在item的展开效果
- spark Task序列化问题
- 男女比例问题