zoukankan      html  css  js  c++  java
  • [loj2393]门票安排

    为了方便,不妨假设$a_{i}\le b_{i}$,并将问题转换为以下形式:

    $\forall 1\le i\le m$,将$[a_{i},b_{i})$或$[1,a_{i})\cup [b_{i},n]$覆盖共$c_{i}$次,最小化覆盖次数最多的位置

    考虑先全部覆盖$[a_{i},b_{i})$,再将若干个区间反转来调整,并且要求最终反转的方案(在取到最小值的基础上)反转的区间个数最少,下面来分析此方案的性质——

    记初始第$i$个位置被覆盖$s_{i}$次,反转后第$i$个位置被覆盖$t_{i}$次

    性质1:反转的区间两两有交

    若存在两个反转的区间不交,撤销反转这两个区间,显然最小值不降且个数减小

    由此,记反转的区间交为$[x,y]$,$[x,y]$中$t_{i}$的最大值为$t_{k}$

    引理:$\forall i\in [x,y],s_{i}-t_{i}=s_{k}-t_{k}$;$\forall i\not\in [x,y],s_{i}-t_{i}\le s_{k}-t_{k}-2$

    注意到$s_{i}-t_{i}$仅取决于$i$被多少个反转的区间覆盖,且每少一个区间值会减小2

    另外,由前者显然可得$s_{k}=\max_{x\le i\le y}s_{i}$,以下不再叙述

    性质2:$t_{k}\ge \max_{1\le i\le n}t_{i}-1$

    若不成立,撤销反转一个$l=x$的区间和一个$r=y$的区间,那么最小值不降且个数减小

    性质3:$\forall s_{j}=\max_{1\le i\le n}s_{i},j\in [x,y]$

    若存在$j\not\in [x,y]$,则$s_{k}-t_{k}\le s_{j}-(t_{j}-1)$(根据性质2),与引理矛盾

    结合上述性质,来考虑如何求出此方案——

    二分枚举答案$T=\max_{1\le i\le n}t_{i}$,取$s_{i}$的最大值为$s_{k}$,再枚举$t_{k}=T$或$T-1$

    由于所有反转区间都包含$k$,即可推出反转的区间个数$cnt=s_{k}-t_{k}$

    记$cnt'_{i}$为包含$i$的反转区间个数,限制即$s_{i}+(cnt-2cnt'_{i})\le T$,不妨写成$cnt'_{i}\ge lim_{i}$的形式

    由此,考虑在满足$i\in [1,k)$的限制基础上,最大化反转区间的右端点

    具体的,从小到大枚举$i$,并维护左端点$\le i$的未反转区间右端点(要求$\ge k$),在$i$上贪心反转右端点最大的$\max(lim_{i}-cnt'_{i},0)$个区间即可

    事实上,之前的性质也适用于"最大覆盖次数$\le T$(而不是取到最小值)且反转的区间个数最少"的反转方案,因此之前的二分显然具备单调性

    时间复杂度为$o(n\log^{2}n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200005
     4 #define ll long long
     5 #define pii pair<int,int>
     6 #define fi first
     7 #define se second
     8 vector<pii>v[N];
     9 priority_queue<pii>q;
    10 int n,m,k,x,y,z;
    11 ll s[N],t[N];
    12 bool check(ll T,ll cnt){
    13     ll Cnt=cnt;
    14     memset(t,0,sizeof(t));
    15     while (!q.empty())q.pop();
    16     for(int i=1;i<=k;i++){
    17         t[i]+=t[i-1];
    18         for(int j=0;j<v[i].size();j++)
    19             if (v[i][j].fi>=k)q.push(v[i][j]);
    20         ll lim=(s[i]+cnt-T+1>>1);
    21         if (i==k)lim=cnt;
    22         while (t[i]<lim){
    23             if (q.empty())return 0;
    24             pii o=q.top();
    25             q.pop();
    26             if (t[i]+o.se<=lim){
    27                 Cnt-=o.se,t[i]+=o.se,t[o.fi]-=o.se;
    28                 continue;
    29             }
    30             int s=lim-t[i];
    31             Cnt-=s,t[i]+=s,t[o.fi]-=s;
    32             q.push(make_pair(o.fi,o.se-s));
    33         }
    34     }
    35     if (Cnt<0)return 0;
    36     for(int i=k+1;i<=n;i++){
    37         t[i]+=t[i-1];
    38         if (s[i]+(cnt-(t[i]<<1))>T)return 0;
    39     }
    40     return 1;
    41 }
    42 bool check(ll T){
    43     return check(T,s[k]-T)|check(T,s[k]-(T-1));
    44 }
    45 int main(){
    46     scanf("%d%d",&n,&m);
    47     for(int i=1;i<=m;i++){
    48         scanf("%d%d%d",&x,&y,&z);
    49         if (x>y)swap(x,y);
    50         s[x]+=z,s[y]-=z;
    51         v[x].push_back(make_pair(y,z));
    52     }
    53     for(int i=1;i<=n;i++)s[i]+=s[i-1];
    54     for(int i=1;i<=n;i++)
    55         if (s[k]<s[i])k=i;
    56     ll l=0,r=s[k];
    57     while (l<r){
    58         ll mid=(l+r>>1);
    59         if (check(mid))r=mid;
    60         else l=mid+1;
    61     }
    62     printf("%lld\n",l);
    63     return 0;
    64 } 
    View Code
  • 相关阅读:
    4个小时实现一个HTML5音乐播放器
    一款好看+极简到不行的HTML5音乐播放器-skPlayer
    操纵浏览器的历史记录
    基于jQuery查找dom的多种方式性能问题
    你真的了解console吗?
    关于overflow:hidden和bfc
    jQuery插件开发
    深入浅出jsonp
    jQuery.extend 函数详解
    [转] Hibernate一级缓存、二级缓存
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15567106.html
Copyright © 2011-2022 走看看