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\n");
73         for(int i=1; i<=n; ++i)
74         {
75             if(i!=n) printf("%c",w[i]);
76             else printf("%c\n",w[i]);
77         }
78     }
79     else
80     {
81         printf("NO\n");
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

 

posted @ 2019-09-14 15:33  kongbursi  阅读(162)  评论(0编辑  收藏  举报