• [ICPC2022Macau]Cyclic Buffer【线段树】【动态规划】


    分析:首先可以设计一个简单的dp。设dp[i][j]表示前i个数已经被选,且当前buffer的左端点在j这个位置的最小代价。注意到这个dp的有用点是很少的(有用点的意思是dp[i][j]不是由dp[i][j-1]或者dp[i][j+1]转移而来的),而且所有的有用点集中在buffer覆盖在第i个数所在的位置上。所有的dp[i][j]的状态都可以由dp[i-1]中的有用点转移而来。然后再思考有用点的性质。

    设j是对i-1的一个有用点,且j~j+k-1覆盖了第i个数所在的位置,那么j对i也是有用点,因为我站在原地不动就可以取到i。

    新增的有用点一定是最左覆盖i和最右覆盖i的两个buffer所在的左端点。

    这时候考虑数据结构维护。对于一个数i,寻找最右覆盖的大于它的mex,最左覆盖的大于它的mex。然后转移的时候直接跳过原地不动可以取到的情况,更新新增的有用点的情况。

    (写的不清不楚,因为是给自己看的)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 1020000;
     5 
     6 int n,k;
     7 int a[maxn*2],b[maxn];
     8 
     9 long long l[maxn],r[maxn];
    10 int nl[maxn],nr[maxn];
    11 
    12 int T[maxn*4];
    13 
    14 void update(long long ori,int rightpos,int upd,long long &ans){
    15     if(upd == -1){ans = min(ans,ori);return;}
    16     long long u1 = ori+min(abs(b[upd]-rightpos),n-abs(b[upd]-rightpos));
    17     if(l[upd] == -1) l[upd] = u1;
    18     else l[upd] = min(l[upd],u1);
    19     int leftpos = (rightpos-k+1+n)%n;if(leftpos == 0) leftpos = n;
    20     long long u2 = ori+min(abs(b[upd]-leftpos),n-abs(b[upd]-leftpos));
    21     if(r[upd] == -1) r[upd] = u2;
    22     else r[upd] = min(r[upd],u2);
    23 }
    24 
    25 void add(int now,int l,int r,int pos,int dt){
    26     if(l == r){T[now]+=dt;return;}
    27     else{
    28     int mid = (l+r)/2;
    29     if(pos <= mid) add(now<<1,l,mid,pos,dt);
    30     else add(now<<1|1,mid+1,r,pos,dt);
    31     T[now]+=dt;
    32     }
    33 }
    34 int query(int now,int tl,int tr,int l,int r){
    35     if(tl >= l && tr <= r){
    36     if(T[now] == tr-tl+1) return -1;
    37     else{
    38         if(tl == tr) return tl;
    39         int mid = (tl+tr)/2;
    40         int how = query(now<<1,tl,mid,l,r);
    41         if(how != -1) return how;
    42         else return query(now<<1|1,mid+1,tr,l,r);
    43     }
    44     }
    45     if(tl > r || tr < l) return -1;
    46     int mid = (tl+tr)/2;
    47     int how = query(now<<1,tl,mid,l,r);
    48     if(how != -1) return how;
    49     else return query(now<<1|1,mid+1,tr,l,r);
    50 }
    51 
    52 int main(){
    53     ios::sync_with_stdio(false);
    54     int t; cin >> t;
    55     while(t--){
    56     cin >> n >> k;
    57     for(int i=1;i<=n;i++) {
    58         cin >> a[i];
    59         a[n+i] = a[i];
    60         b[a[i]] = i;
    61         l[i] = r[i] = -1;
    62         nl[i] = nr[i] = 0;
    63     }
    64     for(int i=k;i>=1;i--) add(1,1,n,a[i],1);
    65     for(int i=n;i>=1;i--){
    66         add(1,1,n,a[i+k],-1);
    67         add(1,1,n,a[i],1);
    68         nr[a[i]] = query(1,1,n,a[i],n);
    69     }
    70     int st = query(1,1,n,1,n);
    71     for(int i=1;i<=4*n;i++) T[i] = 0;
    72     if(st == -1){cout<<0<<endl;continue;}
    73     l[st] = min(abs(b[st]-k),n-abs(k-b[st]));
    74     r[st] = min(b[st]-1,n+1-b[st]);
    75     for(int i=n-k+1;i<=n;i++) add(1,1,n,a[i],1);
    76     for(int i=n+1;i<=2*n;i++){
    77         add(1,1,n,a[i-k],-1);
    78         add(1,1,n,a[i],1);
    79         nl[a[i-n]] = query(1,1,n,a[i],n);
    80     }
    81     for(int i=1;i<=4*n;i++) T[i] = 0;
    82     long long ans = 1e18;
    83     for(int i=st;i<=n;i++){
    84         if(l[i] != -1){
    85         update(l[i],b[i],nl[i],ans);
    86         }
    87         if(r[i] != -1){
    88         update(r[i],((b[i]+k-1)-1)%n+1,nr[i],ans);
    89         }
    90     }
    91     cout<<ans<<endl;
    92     }
    93 }
    View Code
  • 相关阅读:
    转载+自己心得
    分享
    领域驱动设计系列文章汇总
    ABP集合贴
    MVC学习系列——参考
    MVC学习系列——RazorViewEngine扩展
    MVC学习系列——Model验证扩展
    MVC学习系列——HtmlHelper扩展
    MVC学习系列——ModelBinder扩展
    MacBook强制清除gardle缓存
  • 原文地址:https://www.cnblogs.com/Menhera/p/16205214.html
Copyright © 2020-2023  润新知