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
  • 相关阅读:
    Postman使用教程
    CAD和ArcGIS转换 矢量配准
    SAP CRM Advanced search和Simple search里Max hit表现行为的差异
    SAP CRM Product simple search的启用步骤
    如何快速定位SAP CRM订单应用(Order Application)错误消息抛出的准确位置
    如何动态修改SAP CRM WebClient UI表格栏的宽度
    如何在SAP CRM WebClient UI里创建web service并使用ABAP消费
    如何处理SAP CRM Web Service错误
    如何使用SAP CRM WebClient UI实现一个类似新浪微博的字数统计器
    如何开启SAP CRM基于WORD模板创建附件的功能
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15567106.html
Copyright © 2011-2022 走看看