BZOJ1367 [Baltic2004]sequence

来源:互联网 发布:淘宝实名认证可以改吗 编辑:程序博客网 时间:2024/06/14 07:35

这题真是挺tmd神啊

先考虑构造单调不降序列

对于原串中的一个单调下降的区间,肯定是中位数比较优

那么我们把序列化成一个个下降的区间

每次新加进来一个数单算一个区间,然后不断把最后一个区间和倒数第二个合并,还是取中位数,直到最后一个区间的中位数大于等于倒数第二个区间的

用一个可并堆维护中位数即可,只需要保留小于等于中位数的数

对于构造单调上升序列的情况,可以把原序列里的第i个减i

牛B的可以一眼看出是对的

如果一眼看不出的话可以大概感性理解一下或者归纳证明一下?

#include<iostream>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<iomanip>#include<cstdlib>#include<cstdio>#include<map>#include<bitset>#include<set>#include<stack>#include<vector>#include<queue>using namespace std;#define MAXN 1000010#define MAXM 1010#define ll long long#define eps 1e-8#define MOD 1000000007#define INF 1000000000int rt[MAXN],siz[MAXN],r[MAXN],v[MAXN];int son[MAXN][2];int a[MAXN];int n,tp;ll ans;int merge(int x,int y){if(!x||!y){return x+y;}if(v[x]<v[y]){swap(x,y);}siz[x]=siz[x]+siz[y];son[x][1]=merge(son[x][1],y);swap(son[x][1],son[x][0]);return x;}int main(){int i,j;scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d",&a[i]);a[i]-=i;tp++;v[i]=a[i];rt[tp]=i;r[tp]=i;siz[i]=1;while(tp>1&&v[rt[tp]]<v[rt[tp-1]]){tp--;r[tp]=r[tp+1];rt[tp]=merge(rt[tp],rt[tp+1]);while(siz[rt[tp]]*2>r[tp]-r[tp-1]+1){rt[tp]=merge(son[rt[tp]][0],son[rt[tp]][1]);}}}for(i=j=1;i<=tp;i++){for(;j<=r[i];j++){ans+=abs(a[j]-v[rt[i]]);}}printf("%lld\n",ans);return 0;}/*79 4 8 20 14 15 18*/


0 0
原创粉丝点击