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 }
正解:
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 }