zoukankan      html  css  js  c++  java
  • CF1504X Codeforces Round #712

    CF1504D Flip the Cards(找规律+贪心)

    题目大意:给你n张牌,正反面都有数字,保证所有牌上的数字在$[1,2n]$内且互不相同。你可以翻转任意张牌,接下来需要把牌按正面的数字从小到大排序,需要保证排序后牌背面的数字是从大到小。给出初始时牌的状态,问最少需要多少次翻转才能符合要求,如果一定达不到要求则输出-1。 n=1e5

    限制关系是环,难以从前到后直接处理这个长度为2n的序列

    套路1:把序列砍成一半

    我们定义$a[i]$表示数$i$的牌背面的数字是多少。

    多画几个例子容易发现,如果一张牌正反面都$le n$或正反面都$>n$,一定不合法!因为数字各不相同,排的时候剩余的空不够!假设有一张牌的数字都$le n$,那么在$[1,n]$内可用的其他位置为$n-2$个,却还有$n-1$张牌要占位置。都$>n$的情况是同一个道理

    现在只考虑$[1,n]$,我们需要把$a[i]$划分成两个下降子序列!第一个序列i正面$a[i]$负面,第二个序列从后到前,a[i]反面i正面。

    套路2:观察性质

    如果$i$满足$min_{jle i}(a[j]) > max_{j>i}(a[j])$,我们称$i$和$i+1$的间隔是一个间断,间断把序列分成数段,段和段之间的答案不会相互影响,因为段头可以接在任意一个子序列的末尾

    单个段具有特殊性质!如果这段划分成两个下降子序列,那么划分的方式是唯一的

    证明:

    假设这一段是$[l,r]$,那么只有唯一的一个$xin(l,r],a[x]>a[l]$

    对于$iin (l,r]$

    1.要么存在$lle j<i$,$a[j]<a[i]$,$i$和$j$一定不在一组

    2.要么存在$i<kle r$,$a[k]>a[i]$,$k$和$i$不在一组

    对于$(l,x)$的位置,一定和l划分到一组。在这之后,l开头一组,x开头一组。现在需要证明$(x,r]$之间的划分方式唯一

    如果$a[i]$小于l的序列的末尾元素,似乎可以把i分到l或者x的末尾。但它一定不满足性质1,则性质2成立,它必须和k不在同一组。如果k满足性质2,对应的位置是k',那么i,k,k'都不在同一组,一定不合法,因此k只能满足性质1,与i不在同一组。如果a[i]大于l的末尾元素,则只可能放在x的末尾。

    当遍历到x+1是,l组的末尾(也就是x-1)满足性质2,x-1对应的k一定不和l一组,只能和x一组。归纳到(x,r]的其他位置,唯一确定了这一段的划分方式

    综上,我们只需要关心l是正还是反就行了,正反两种情况讨论一下取最小值即可

     1 const int maxn=400000,N1=maxn+5; const int inf=0x3f3f3f3f;
     2 
     3 int n;
     4 template <typename _T> void read(_T &ret)
     5 {
     6     ret=0; _T fh=1; char c=getchar();
     7     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     8     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     9     ret=ret*fh;
    10 }
    11 int oa[N1],ob[N1],a[N1], type[N1];
    12 int sma[N1],smi[N1];
    13 
    14 int mi[2];
    15 int check(int l,int r,int p)
    16 {
    17     mi[p]=a[l]; mi[p^1]=inf; int ans=type[l]^p;
    18     for(int i=l+1;i<=r;i++) 
    19     {
    20         if(a[i]>max(mi[p],mi[p^1])) return -1;
    21         if(mi[p]<mi[p^1]){
    22             if(a[i]<mi[p]) mi[p]=a[i], ans+=type[i]^p;
    23             else mi[p^1]=a[i], ans+=type[i]^p^1;
    24         }else{
    25             if(a[i]<mi[p^1]) mi[p^1]=a[i], ans+=type[i]^p^1;
    26             else mi[p]=a[i], ans+=type[i]^p;
    27         }
    28     }
    29     return ans;
    30 }
    31 int calc(int l,int r)
    32 {
    33     return min(check(l,r,1),check(l,r,0));
    34 }
    35 int solve()
    36 {
    37     int ans=0, tmp;
    38     for(int i=1,j=1;i<=n;i++)
    39     {
    40         for(j=i;j<n&&smi[j]<=sma[j+1];j++);
    41         tmp=calc(i,j); if(tmp==-1) return -1;
    42         ans+=tmp;
    43         i=j;
    44     }
    45     return ans;
    46 }
    47 
    48 int main()
    49 {
    50     scanf("%d",&n);
    51     for(int i=1;i<=n;i++)
    52     {
    53         read(oa[i]), read(ob[i]);
    54         if( (oa[i]<=n && ob[i]<=n) || (oa[i]>n && ob[i]>n) ){ puts("-1"); return 0; }
    55         if(oa[i]<=n) a[oa[i]]=ob[i]; else a[ob[i]]=oa[i], type[ob[i]]=1;
    56     }
    57     smi[0]=inf;
    58     for(int i=1;i<=n;i++) smi[i]=min(smi[i-1],a[i]);
    59     for(int i=n;i>=1;i--) sma[i]=max(sma[i+1],a[i]);
    60     int ans=solve();
    61     printf("%d
    ",ans);
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    数据绑定表达式语法(Eval,Bind区别)
    使用博客园的第一件事 自定义主题
    sql2000 跨服务器复制表数据
    使用UpdatePanel 局部刷新出现中文乱码的解决方法!!
    MMC不能打开文件MSC文件
    sql 日期 、时间相关
    loaded AS2 swf call function in AS3 holder
    Rewrite the master page form action attribute in asp.net 2.0
    100万个不重复的8位的随机数
    flash 中实现斜切变型
  • 原文地址:https://www.cnblogs.com/guapisolo/p/14641683.html
Copyright © 2011-2022 走看看