zoukankan      html  css  js  c++  java
  • [atAGC047F]Rooks

    如果将$x$和$y$都离散,那么删除的点的$x_{i}$和$y_{i}$必然都组成了一个完整的区间(包括过程中)

    将所有点按$x$排序,再令$f[i][j][0/1]$表示当删除完区间$[i,j]$且位于点$i$/点$j$时答案(若无法删除记为$infty$),转移考虑下一次删除的点($i-1$或$j+1$)是否可行

    (这里的答案指在这个状态后删除尽量多的点所需最短时间,因此最终答案为$f[i][i][0/1]$,初始状态不易确定,可以记忆化搜索来做,当无法转移即为0)

    根据上面的结论,记$mn=min_{ile kle j}y_{k}$、$mx=max_{ile kle j}y_{k}$,假设下一次选了$i-1$,那么即要求$y_{i-1}$等于$mn-1$或$mx+1$(选$j+1$同理),由此判定时间复杂度为$o(n^{2})$

    贪心,对于存在区间$[i,j]$满足$forall ile k<j,|y'_{k}-y'_{k+1}|=1$,当我们删除了$i$接下来必然删除$i+1,...,j$(删除$j$同理),因此不妨将其缩为1个点(仅是视为一个点),但此时复杂度貌似仍然是$o(n^{2})$的

    定义一个区间合法当且仅当其在记忆化搜索过程中会被得到,时间复杂度即为合法区间数

    一个更有意义的判定方法,区间$[i,j]$合法当且仅当$mx-mn=j-i$且可以通过不断删除两端的最小值或最大值使其为空(即若$y_{i}=mn或mx$即可删除$i$,$j$同理)

    对于删除,我们可以贪心,可以发现删除后一定“更容易”删除,即若一个区间合法,任意合法的删除顺序都可以将其删除

    定义$S_{l,r}$表示区间$[l,r]$的子合法区间数,$Sl_{l,r}$表示区间$[l,r]$以$l$为左端点的子合法区间数,$Sr_{l,r}$类似(即以$r$为右端点)

    对一个合法区间$[l,r]$,考虑如何转移求$S_{l,r}$,分类讨论:

    1.$l$和$r$都可以删除,$S_{l,r}=Sl_{l,r-1}+Sr_{l+1,r}+S_{l-1,r-1}+1$

    2.$l$和$r$中只有一个可以删除(假设为$l$),$S_{l,r}=S_{l+1,r}+1$

    来考虑第一种情况中$Sl_{l,r-1}$的级别,不妨假设$l$为$[l,r]$区间最小值,则$r$必然为区间最大值,然后对于$a_{l}+1$的位置分类讨论:

    1.若$a_{l}+1$位于$r-1$,即$a_{r-1}=a_{l}+1$,那么$Sl_{l,r-1}le 2$($[l,l]$,$[l,r-1]$)

    2.若$a_{l}+1$位于$l+1$,即$a_{l+1}=a_{l}+1$,则一定被缩点了,不存在该情况;

    3.否则$a_{l+1}$和$a_{r-1}$必然都不是$[l+1,r-1]$区间最小值,同时若$a_{r-1}$为区间最大值必然满足$a_{r-1}=a_{r}-1$,会被缩点,因此只能$a_{l+1}=a_{r}-1$,那么为了保证$[a_{l},a_{l+1}]$中的数都出现,$Sl_{l,r-1}le 2$

    因此$S_{l,r}$为$o(r-l)$的级别,总合法区间数为$o(n)$级别

    另外,由于要记忆化搜索记录,需要map维护,最终时间复杂度为$o(nlog_{2}n)$,可以通过

    (还有一个细节,可以通过八个方向走到给定点,但平时只能走到相邻的4个方向,相当于可以减少$r-l$步,这个可以在无法转移时记录)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200005
     4 #define ll long long
     5 struct ji{
     6     int x,y,id;
     7 }a[N];
     8 vector<int>v;
     9 map<int,ll>f[2][N];
    10 int n,ls[N],rs[N];
    11 ll ans[N];
    12 bool cmp(ji x,ji y){
    13     return x.x<y.x; 
    14 }
    15 int dis(ji x,ji y){
    16     return abs(x.x-y.x)+abs(v[x.y]-v[y.y]);
    17 }
    18 ll dp(int l,int r,int mn,int mx,int p){
    19     if (f[p][l][r])return f[p][l][r];
    20     f[p][l][r]=1e15;
    21     ji o=a[l+p*(r-l)];
    22     if ((l>1)&&((a[l-1].y==mn-1)||(a[l-1].y==mx+1))){
    23         int k=ls[l-1];
    24         f[p][l][r]=min(f[p][l][r],dp(k,r,min(mn,a[k].y),max(mx,a[k].y),0)+dis(o,a[k]));
    25     }
    26     if ((r<n)&&((a[r+1].y==mn-1)||(a[r+1].y==mx+1))){
    27         int k=rs[r+1];
    28         f[p][l][r]=min(f[p][l][r],dp(l,k,min(mn,a[k].y),max(mx,a[k].y),1)+dis(o,a[k]));
    29     }
    30     if (f[p][l][r]==1e15)f[p][l][r]=-(r-l);
    31     return f[p][l][r];
    32 }
    33 int main(){
    34     scanf("%d",&n);
    35     for(int i=1;i<=n;i++){
    36         scanf("%d%d",&a[i].x,&a[i].y);
    37         a[i].id=i;
    38         v.push_back(a[i].y);
    39     }
    40     sort(v.begin(),v.end());
    41     for(int i=1;i<=n;i++)a[i].y=lower_bound(v.begin(),v.end(),a[i].y)-v.begin();
    42     sort(a+1,a+n+1,cmp);
    43     ls[1]=1,rs[n]=n;
    44     for(int i=2;i<=n;i++)
    45         if (abs(a[i-1].y-a[i].y)!=1)ls[i]=i;
    46         else ls[i]=ls[i-1];
    47     for(int i=n-1;i;i--)
    48         if (abs(a[i+1].y-a[i].y)!=1)rs[i]=i;
    49         else rs[i]=rs[i+1];
    50     for(int i=1;i<=n;i++)ans[a[i].id]=dp(i,i,a[i].y,a[i].y,0);
    51     for(int i=1;i<=n;i++)printf("%lld
    ",ans[i]);
    52 } 
    View Code
  • 相关阅读:
    并发编程3
    并发编程2
    4/23
    4/22
    并发编程1
    粘包问题
    Navicat12激活
    IDEA创建maven项目报错解决:Failed to create a Maven project: 'C:/Users/../IdeaProjects/../pom.xml' already e
    IDEA
    windows下查看端口运行情况--解决端口冲突问题
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13917618.html
Copyright © 2011-2022 走看看