JOISC2019|201920190622cake3
Posted paul-guderian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JOISC2019|201920190622cake3相关的知识,希望对你有一定的参考价值。
题目
\(N\) 个物品中选\(M\)个,排列成一个环:\(k_1,\cdots,k_M\)价值为:
\[
\sum_j=1^NV_i - \sum_j=1^M|C_k_j- C_k_j\%M+1 |
\]
$3 \le N,M \le 2\times 10^5 $
题解
对于一个\(k\),\(C\)最小的排列的贡献是\(2\ ( max - min)\)
因为将 $ k $ 按 $ C $ 排序,由于最终是一个环, $ C_k_j - C_k_j+1 $ 一定会被至少经过两次
将物品按\(C\)排序,枚举最大点,枚举最小点,中间选\(V\)最大的
可以发现从左向右枚举右端点,最小值的选择是单调的
但是单调可能是不连续的,接下来有一个套路:
计算\([l,r]\)的值时,可以先找\(mid = (l + r) /2\) 的最优决策点\(pos_mid\)
那么\(pos_[l,mid-1] \le pos_mid \ , \ pos_[mid+1,r] \ge pos_mid\) ,分治求下去
需要查找区间前\(m-2\)大的和,如果用主席树实现
时间复杂度:\(O(N \log^2 N )\)
#include<bits/stdc++.h> #define ll long long #define inf 1e18 using namespace std; const int N=200010,M=20; int n,m,st[N],tp,sub[N],tot,sz,cnt[N*M],ls[N*M],rs[N*M],rt[N]; ll sum[N*M],a[N],b[N],ans=-inf; struct dataint x,y;A[N]; bool operator <(data X,data Y)return X.y<Y.y; void ins(int&k,int lst,int l,int r,int x,int y) sum[k=++sz]=sum[lst]+y;cnt[k]=cnt[lst]+1; ls[k]=ls[lst],rs[k]=rs[lst]; if(l==r)return; int mid=(l+r)>>1; if(x<=mid)ins(ls[k],ls[lst],l,mid,x,y); else ins(rs[k],rs[lst],mid+1,r,x,y); ll query(int k,int lst,int l,int r,int x) if(l==r||!x)return 1ll*sub[l]*x; int mid=(l+r)>>1,tmp=cnt[rs[k]]-cnt[rs[lst]]; if(x<tmp)return query(rs[k],rs[lst],mid+1,r,x); return sum[rs[k]]-sum[rs[lst]]+query(ls[k],ls[lst],l,mid,x-tmp); ll cal(int l,int r) if(r-l+1<m)return -inf; return a[l]+b[r]+query(rt[r-1],rt[l],1,tot,m-2); void solve(int L,int R,int l,int r) if(L>R)return; if(l==r)for(int i=L;i<=R;++i)ans=max(ans,cal(st[l],i)); int Mid=(L+R)>>1,mid=l;ll tmp=-inf; for(int i=l;i<=r;++i) ll now=cal(st[i],Mid); if(tmp<now)tmp=now,mid=i; ans=max(ans,tmp); solve(L,Mid-1,l,mid); solve(Mid+1,R,mid,r); int main() freopen("cake3.in","r",stdin); freopen("cake3.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d%d",&A[i].x,&A[i].y); sub[++tot]=A[i].x; sort(sub+1,sub+tot+1); tot=unique(sub+1,sub+tot+1)-sub-1; sort(A+1,A+n+1); for(int i=1;i<=n;++i) int pos=lower_bound(sub+1,sub+tot+1,A[i].x)-sub; ins(rt[i],rt[i-1],1,tot,pos,A[i].x); a[i]=A[i].x+2ll*A[i].y; b[i]=A[i].x-2ll*A[i].y; if(!tp||a[i]>a[st[tp]])st[++tp]=i; solve(m,n,1,tp); /*ll ans=cal(1,m); for(int i=m,j=1;i<=n;++i) while(j<tp&&st[j+1]+m-1<=i&&cal(st[j],i)<cal(st[j+1],i))j++; ans=max(ans,cal(st[j],i)); for(int k=1;k<=tp&&st[k]+m-1<=i;++k) printf("%lld ",cal(st[k],i)); puts(""); */ //这段是不对的,因为并不是所有单调都是连续的 //像斜率优化的那种可以用单调队列维护的只是单调的一种特殊情况 //不单调可以用分治做 //20190623 cout<<ans<<endl; return 0;
以上是关于JOISC2019|201920190622cake3的主要内容,如果未能解决你的问题,请参考以下文章