BZOJ4167: 永远亭的竹笋采摘 分块
题意:给定一个序列,将其分成K段,每段元素不得全相同,求sigma(每段中不同元素差值的最小值)的最小值
n<=50000,k<=1000,序列中元素<=n,序列随机生成
既然序列是随机的,我们可以想到一个区间可能要延伸很长一段才会改变其中的最小差值,那么不妨将所有有贡献的点对都枚举出来(即:这个区间的两个端点之差是整个区间中最小的),问题就转化成了在数轴上有一些带权值的线段,选择K条不相交的使权值和最小,这个对于每个点枚举以他为结尾的线段进行转移即可。现在考虑如何求出所有点对。因为点对的分布很稀疏,暴力枚举就会枚举到大量无用的点对,那么不妨使用分块加速索引,每一块预处理出对于每一种权值块内元素中与其差值最小的是多少。那么对于每一个点,枚举后面的块,若最小差值能更新当前值就暴力在块内扫一遍,然后由于要保证两端点差值是最小的,因此枚举左端点时要从右往左,然后使用树状数组检查之前是否已经有点对右端点更靠左且差值更小即可。实测最后的点对数量是O(N)级别的。
代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define gm 50001
#define abs _Abs
const int inf=0x7f7f7f7f;
int n,k,w,size,a[gm];
int c[gm];
int dis[gm][250];
inline int min(int a,int b){return a<b?a:b;}
inline int abs(int a){return a>>31?-a:a;}
struct e
{int t;e *n;int c;e(int t,e *n,int c):t(t),n(n),c(c){}
}*f[gm];
inline void push(int pos,int v)
{for(;pos<=n;pos+=pos&-pos)c[pos]=min(c[pos],v);
}
inline int get(int pos)
{int v=inf;for(;pos;pos-=pos&-pos)v=min(v,c[pos]);return v;
}
void setup()
{memset(c,0x7f,n+1<<2);static int b[250];for(int i=1;i<=w;++i){int l=(i-1)*size+1,r=min(i*size,n);int top=0;for(;l<=r;++l) b[++top]=a[l];std::sort(b+1,b+top+1);int p1=0,p2=1;for(int j=1;j<=n;++j){int &kre=dis[j][i]=inf;while(p1<top&&b[p1+1]<j) ++p1;while(p2<=top&&b[p2]<=j) ++p2;if(p1!=0) kre=min(kre,j-b[p1]);if(p2!=top+1) kre=min(kre,b[p2]-j);}}
}
void tour(int no,int block,int &ans,int beg)
{int end=min(block*size,n);for(;beg<=end;++beg){int kre=abs(a[no]-a[beg]);if(kre&&kre<ans){ans=kre;int cmp=get(beg);if(ans<cmp){push(beg,ans);f[beg]=new e(no,f[beg],ans);}}}
}
int F[gm][1001];
int DP()
{memset(F,0x7f,sizeof F);F[0][0]=0;for(int i=1;i<=n;++i){F[i][0]=0;for(int j=1;j<=k;++j){int &ans=F[i][j]=F[i-1][j];for(e *l=f[i];l;l=l->n)ans=min(ans,F[l->t-1][j-1]+l->c);if(ans==inf) break;}}return F[n][k];
}
int main()
{scanf("%d%d",&n,&k);size=ceil(sqrt(n));w=(n-1)/size+1;for(int i=1;i<=n;++i) scanf("%d",a+i);setup();for(int i=n;i;--i){int j=(i-1)/size+1;int len=inf;tour(i,j,len,i+1);for(++j;j<=w;++j)if(dis[a[i]][j]<len)tour(i,j,len,(j-1)*size+1);}printf("%d\n",DP());return 0;
}
BZOJ4167: 永远亭的竹笋采摘 分块相关推荐
- bzoj4167 永远亭的竹笋采摘
由于是随机数据,用分块加乱搞就可以水过. 详情参见大佬的博客:题解 贴个代码: #include<cstdio> #include<cstring> #include<v ...
- HN2015集训 永远亭的竹笋采摘
第一反应肯定是dp啦,然后就会愉快的T成一头象拔蚌. 那么,说说正解吧. 显然,选取的区间一定可以是两头为差值最小的.那就好办了,只需要预处理出所有的这样的区间,再dp即可,由于数据是随机生成的,所以 ...
- BZOJ4167 : 永远的竹笋采摘
首先枚举出所有可能成为区间最小差值的点对$(j,i)$. 枚举每个位置作为右端点$i$,假设$a[j]>a[i]$. 找到第一个这样的$j$,那么可以将下一个$a[j]$的范围缩小到$(a[i] ...
- 数据分析与预测(二)——pandas 函数read_csv解析
一. 前言 使用pandas做数据处理的第一步就是读取数据,数据源可以来自于各种地方,csv文件便是其中之一.而读取csv文件,pandas也提供了非常强力的支持,参数有四五十个.这些参数中,有的 ...
- 东方mmd巨大化_有什么东方mmd非常值得一看?
1.月之头脑是处方(月の頭脳は処方せん):以铃仙·优昙华院前往红魔馆送药的旅程为起点,穿插魔理沙误捡药物产生的误会,以及比那名居 天子/射命丸 文的煽动,当然结尾众人都获得一个圆满结局. 2.魔理沙的 ...
- codevs2830 蓬莱山辉夜
2830 蓬莱山辉夜 题目描述 Description 在幻想乡中,蓬莱山辉夜是月球公主,居住在永远亭上,二次设定说她成天宅在家里玩电脑,亦称NEET姬 一天,她要她帮忙升级月球的网络服务器,应为注册 ...
- codevs 2830 蓬莱山辉夜
codevs 2830 蓬莱山辉夜 在幻想乡中,蓬莱山辉夜是月球公主,居住在永远亭上,二次设定说她成天宅在家里玩电脑,亦称NEET姬 一天,她要她帮忙升级月球的网络服务器,应为注册用户过多(月兔和地球 ...
- 【codevs 2830】蓬莱山辉夜
作为一个有图的题,竟然描述如此不清楚,表示愤慨 其实就是个堆--可这是个语文题啊语文题!!!! 题目描述 在幻想乡中,蓬莱山辉夜是月球公主,居住在永远亭上,二次设定说她成天宅在家里玩电脑,亦称NEET ...
- 2830 蓬莱山辉夜 优先队列的简单应用
在幻想乡中,蓬莱山辉夜是月球公主,居住在永远亭上,二次设定说她成天宅在家里玩电脑,亦称NEET姬 一天,她要她帮忙升级月球的网络服务器,应为注册用户过多(月兔和地球上的巫女都注册了--),所以作为代理 ...
最新文章
- 砸500万买学位房,一个焦虑中产的看房日记
- 适用于System Center 2016所需前期准备工作
- Majority Element
- 25、HTML 文本格式化
- @autowired注解原理_相见恨晚,一个架构师也不会用的Lombok注解
- cmd 无法切换目录
- Multiverse: Revolutionary Backend for Alembic // Multiverse: 下一代Alembic后端
- 05.序列模型 W2.自然语言处理与词嵌入(作业:词向量+Emoji表情生成)
- 使用FragmentTabHost+Fragment+viewpager 实现滑动分页
- SQL函数学习 之 DENSE_RANK() OVER (PARTITION BY col2 ORDER BY col3 DESC) AS seq
- HUE与HDFS的集成
- sql语句distinct_带DISTINCT子句SQL SELECT语句
- 如何在浏览器上安装 VueDevtools工具
- linux命令大全之ss命令详解(获取socket统计信息)
- 利用python从网络上爬取图片_我用Python爬取了妹子网100G的套图
- 装逼技能:怎样优雅地摆放桌面图标?
- Java程序强制删除文件
- 基于模型的约束排序,并探究OTUs对pH的响应特征——单峰or线性?
- 如何获取多屏幕显示器工作区域
- java osm_OSM初识(三)OSM Data