【枚举】【权值分块】bzoj1112 [POI2008]砖块Klo

枚举长度为m的所有段,尝试用中位数更新答案。

所以需要数据结构,支持查询k大,以及大于/小于 k大值 的数的和。

平衡树、权值线段树、权值分块什么的随便呢。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 typedef long long ll;
 6 struct Point{int v,p;}t[100001];
 7 bool operator < (const Point &a,const Point &b){return a.v<b.v;}
 8 int sumv[350],ma[100001],en,a[100001],b[100001],tot[350],l[350],r[350],num[100001],sum=1,K,n,m;
 9 ll ans=999999999999999999,tAns;
10 void makeblock()
11 {
12     int sz=sqrt(en); if(!sz) sz=1;
13     for(;sum*sz<en;++sum)
14       {
15           l[sum]=r[sum-1]+1; r[sum]=sum*sz;
16           for(int i=l[sum];i<=r[sum];++i) num[i]=sum;
17       }
18     l[sum]=r[sum-1]+1; r[sum]=en;
19     for(int i=l[sum];i<=r[sum];++i) num[i]=sum;
20 }
21 void Insert(const int &x){++b[x]; ++tot[num[x]]; sumv[num[x]]+=(ll)ma[x];}
22 void Delete(const int &x){--b[x]; --tot[num[x]]; sumv[num[x]]-=(ll)ma[x];}
23 int Query(const int &x)
24 {
25     int cnt=0; ll now=0;
26     for(int i=1;;i++)
27       {
28         cnt+=tot[i]; now+=sumv[i];
29         if(cnt>=x)
30           {
31               cnt-=tot[i]; now-=sumv[i];
32             for(int j=l[i];;j++)
33               {
34                 cnt+=b[j]; now+=(ll)ma[j]*(ll)b[j];
35                 if(cnt>=x)
36                   {
37                       cnt-=b[j]; now-=(ll)ma[j]*(ll)b[j];
38                       tAns=((ll)ma[j]*(ll)cnt-now);
39                       return j;
40                   }
41               }
42           }
43       }
44 }
45 void Next_Sum(const int &x)
46 {
47     int cnt=0; ll now=0;
48     for(int i=x+1;i<=r[num[x]];++i) {cnt+=b[i]; now+=(ll)ma[i]*(ll)b[i];}
49     for(int i=num[x]+1;i<=sum;++i) {cnt+=tot[i]; now+=sumv[i];}
50     tAns+=(now-(ll)ma[x]*(ll)cnt);
51 }
52 int main()
53 {
54     scanf("%d%d",&n,&m); K=(m>>1)+1;
55     for(int i=1;i<=n;++i)
56       {
57           scanf("%d",&t[i].v);
58           t[i].p=i;
59       } sort(t+1,t+n+1);
60     ma[a[t[1].p]=++en]=t[1].v;
61     for(int i=2;i<=n;++i)
62       {
63           if(t[i].v!=t[i-1].v) ++en;
64           ma[a[t[i].p]=en]=t[i].v;
65       } makeblock();
66     for(int i=1;i<=m;++i) Insert(a[i]);
67     int t=Query(K); Next_Sum(t); ans=min(ans,tAns);
68     for(int i=m+1;i<=n;++i)
69       {
70           Delete(a[i-m]); Insert(a[i]);
71           int t=Query(K);
72         Next_Sum(t);
73         ans=min(ans,tAns);
74       } printf("%lld\n",ans);
75     return 0;
76 }
时间: 2024-10-21 09:45:49

【枚举】【权值分块】bzoj1112 [POI2008]砖块Klo的相关文章

bzoj1112[POI2008]砖块Klo*

bzoj1112[POI2008]砖块Klo 题意: N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:丢掉某柱砖的一块砖.给某柱加上一块砖,现在希望用最小次数的动作完成任务.N≤100000 题解: 设一个区间长度为k,其中位数为a,比a小的元素个数为b,和为c:比a大的元素个数为d,和为e.则题目要求维护一个长度为k的滑动窗口,能求出它的b*a-c+e-d*a.故用一个维护sum,size两个值的treap来维护.然而似乎我想复杂了?比所有人代码都大1k!注意要开long

[BZOJ1112] [POI2008] 砖块Klo (treap)

Description N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. Input 第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000 Output 最小的动作次数 Sample Input 5 3 3 9 2 3 1 Sample Output 2 HINT 原题还要求输

1112: [POI2008]砖块Klo

1112: [POI2008]砖块Klo Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1245  Solved: 426[Submit][Status][Discuss] Description N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. Input 第一行给出N,K. (1 ≤ k ≤ n ≤

【DFS序列】【莫队算法】【权值分块】bzoj2809 [Apio2012]dispatching

题意:在树中找到一个点i,并且找到这个点子树中的一些点组成一个集合,使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大 首先,我们将树处理出dfs序,将子树询问转化成区间询问. 然后我们发现,对于单一节点来说,“使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大”可以贪心地搞,即优先选择c较小的点.(<--这正是主席树/权值线段树/权值分块的工作) 但是我们需要枚举所有节点,从他们中选一个最大的. 既然有dfs序了,那么就是无修改的区间询问咯.(<--莫队的工作)

BZOJ 1112: [POI2008]砖块Klo

1112: [POI2008]砖块Klo Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1736  Solved: 606[Submit][Status][Discuss] Description N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. Input 第一行给出N,K. (1 ≤ k ≤ n ≤

【莫队算法】【权值分块】bzoj3920 Yuuna的礼物

[算法一] 暴力. 可以通过第0.1号测试点. 预计得分:20分. [算法二] 经典问题:区间众数,数据范围也不是很大,因此我们可以: ①分块,离散化,预处理出: <1>前i块中x出现的次数(差分): <2>第i块到第j块中的众数是谁,出现了多少次. 询问的时候,对于整块的部分直接获得答案:对于零散的部分,暴力统计每个数出现 的次数,加上差分的结果,尝试更新ans. 时间复杂度O(m*sqrt(n)), 空间复杂度O(n*sqrt(n)). ②考虑离线,莫队算法,转移的时候使用数据

【权值分块】bzoj3570 DZY Loves Physics I

以下部分来自:http://www.cnblogs.com/zhuohan123/p/3726306.html DZY系列. 这题首先是几个性质: 1.所有球质量相同,碰撞直接交换速度,而球又没有编号,那么就可以直接视作两个球没有碰撞. 2.所有的方向.初始位置都没有任何用处. 然后就是速度的问题了,根据题设 a⋅v=C 与这几个方程联立 a⋅v=C s=v·t; vt2=v02+2·a·s 解这个方程组,可以得到 vt=√(2·C·t+v02) 那么T时刻的速度vT的相对大小就直接由v0决定了

【权值分块】bzoj1861 [Zjoi2006]Book 书架

权值分块……rank3……没什么好说的. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 int n,sz,sum,x,y,l[501],r[501],Min,Max,sumv[501],num[250001],m,v[250001],p[250001]; 6 bool b[250001]; 7 char op[6],c; 8 int Num,CH[1

【树链剖分】【函数式权值分块】bzoj1146 [CTSC2008]网络管理Network

裸题,直接上.复杂度O(n*sqrt(n)*log(n)). //Num[i]表示树中的点i在函数式权值分块中对应的点 //Map[i]表示函数式权值分块中的点i在树中对应的点 #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 80001 #define INF 2147483647 #define NN 87001 #define BN 296 int