• Codeforces Round #582 (Div. 3) F. Unstable String Sort


    传送门

    题意:

    你需要输出一个长度为n的字符序列(由小写字母组成),且这个字符串中至少包含k个不同的字符。另外题目还有要求:给你两个长度为p和q的序列,设字符序列存在s中

    那么就会有s[Pi]<=s[P(i+1)]   (i<p)    

         s[Qi]<=s[Q(i+1)]   (i<q)   如果你能找出来满足这些条件的字符串s,就输出YES和s,否则输出NO

    这会得到一个非递减字符串

    题解:

     因为最后的结果是一个非递减字符串,那么肯定对整个字符串s,会有s[i]<=s[i+1] (0<=i<strlen(s)-1)

    那么这样的话,只有当Pi>P(i+1)或者Qi>Q(i+1)的时候,才会影响字符串在[P(i+1),Pi]或者[Q(i+1),Qi]的取值,这一段区间内的字符肯定要相等

    因为题目上要求字符串s至少要有k个不同的字符,所以只要不遇到上面这种情况,那么每一个位置的字符都要比上一个字符大(我们这里是先用a,再用b等等)

    所以我们只需要注意Pi>P(i+1)或者Qi>Q(i+1)这种区间就可以了

    想到这里正解就出来了,对每个P[i]找到最小的jjj,使得P[j]的位置在Q中位于P[i]的后方(为了方便,认为i自身也是一个合法的jjj),那么P[j..i]就必须同字母。如果两个同字母段相交,那么合并起来的整一段都必须同字母,因此处理完所有字母段再扫一遍,把相交的同字母段合并。最后看看有没有k段,贪心地让不同字母段用不同的字母即可,复杂度O(n)

    如果用到了字符z,但是序列s还没有写完,那么剩下的全部位置输出z

    如果抛开题目去看,你输出一个长为n的序列,如果这个序列中只包含一个字符,那么除了不满足k个不同字符的要求外,其他条件都满足

    还有一种方法,P[i]]向P[i−1]连边,Q[i]则Q[i−1]连边,边(x,y)就表示x位置上的字母必须不小于y位置,那么一个强连通分量的所有位置必须同字母,一遍tarjan即可

    我原来写了一个,但是过于暴力,T了T_T

    T代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<vector>
     6 #include<queue>
     7 using namespace std;
     8 const int maxn=2e5+5;
     9 const int INF=0x3f3f3f3f;
    10 typedef long long ll;
    11 //vector<int>w[maxn];
    12 int a[maxn],b[maxn],v[maxn],w[maxn];
    13 int main()
    14 {
    15     int n,k;
    16     //memset(v,INF,sizeof(v));
    17     scanf("%d%d",&n,&k);
    18     for(int i=1; i<=n; ++i)
    19     {
    20         scanf("%d",&a[i]);
    21     }
    22     for(int i=1; i<=n; ++i)
    23         scanf("%d",&b[i]);
    24     for(int i=1; i<n; ++i)
    25     {
    26         if(a[i+1]<a[i])
    27         {
    28             v[a[i+1]]=max(v[a[i+1]],a[i]);
    29         }
    30     }
    31     for(int i=1; i<n; ++i)
    32     {
    33         if(b[i+1]<b[i])
    34         {
    35             v[b[i+1]]=max(v[b[i+1]],b[i]);
    36         }
    37     }
    38     int ans=0,flag=0;
    39     for(int i=1; i<=n; ++i)
    40     {
    41         if(w[i]==0)
    42         {
    43             if(v[i]==0)
    44             {
    45                 w[i]='a'+ans++;
    46             }
    47             else
    48             {
    49                 for(int j=i; j<=v[i]; ++j)
    50                     w[j]='a'+ans;
    51                 ans++;
    52                 //i=v[i];
    53             }
    54         }
    55         else
    56         {
    57             if(v[i]==0)
    58             {
    59                 continue;
    60             }
    61             else
    62             {
    63                 for(int j=i+1; j<=v[i]; ++j)
    64                     w[j]=w[i];
    65                 //i=v[i];
    66             }
    67         }
    68     }
    69     if(ans<k) flag=1;
    70     if(!flag)
    71     {
    72         printf("YES
    ");
    73         for(int i=1; i<=n; ++i)
    74         {
    75             if(i!=n) printf("%c",w[i]);
    76             else printf("%c
    ",w[i]);
    77         }
    78     }
    79     else
    80     {
    81         printf("NO
    ");
    82     }
    83     return 0;
    84 }
    View Code

    正解:

     1 #include<stdio.h>
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<queue>
     5 #include<cmath>
     6 #include<string.h>
     7 #include<set>
     8 #define LL long long
     9 using namespace std;
    10 LL read( )
    11 {
    12   LL sum=0;char c=getchar( );bool f=0;
    13   while(c<'0' || c>'9') {if(c=='-') f=1;c=getchar( );}
    14   while(c>='0' && c<='9') {sum=sum*10+c-'0';c=getchar( );}
    15   if(f) return -sum;
    16   return sum;
    17 }
    18 const int N=200005;
    19 int n,m,P[N],Q[N],pos[N],L[N],bel[N];
    20 char ans[N];
    21 int main( )
    22 {
    23   int i,j,k;
    24   n=read( );m=read( );
    25   for(i=1;i<=n;i++) P[i]=read( ),pos[P[i]]=i;
    26   for(i=1;i<=n;i++) Q[i]=read( );
    27   for(k=n,i=n;i>=1;i--) j=pos[Q[i]],k=min(k,j),L[j]=k;
    28   for(j=1,k=n,i=n;i>=1;i--)
    29     {
    30       k=min(k,L[i]);bel[i]=j;
    31       if(k==i) j++;
    32     }
    33   if(bel[1]<m) {puts("NO");return 0;}
    34   puts("YES");
    35   for(j=-1,i=1;i<=n;i++)
    36     {
    37       if(bel[i]!=bel[i-1]) j++;
    38       ans[P[i]]='a'+min(25,j);
    39     }
    40   for(i=1;i<=n;i++) printf("%c",ans[i]);
    41   return 0;
    42 }
    View Code
  • 相关阅读:
    [国家集训队]数颜色 / 维护队列
    [SP3267]DQUERY
    扩展欧几里得算法详解(exgcd)
    [CTSC2018]混合果汁
    极角排序那些事
    向量的点乘与叉乘学习笔记
    [APIO2014]序列分割
    CF1148D-Dirty Deeds Done Dirt Cheap
    CF176E Archaeology(set用法提示)
    【网络流24题】最长不下降子序列问题
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11519274.html
Copyright © 2020-2023  润新知