Codeforces 1296E2 - String Coloring (hard version)

题目大意:

给定一段长度为n的字符串s

你需要给每个字符进行涂色,然后相邻的不同色的字符可以进行交换

需要保证涂色后能通过相邻交换把这个字符串按照字典序排序(a~z)

你可以使用无限种颜色,但是要保证用到的颜色种类最少

从1开始对颜色进行编号,先输出最少使用的颜色种类,再给出涂色方案

解题思路 1:

可以引入一个 r 数组,开26个空间代表26种字母

这个数组 r[i] 的值代表 第 i 个字母在前面涂的颜色最大编号是多少,0表示没出现过

遍历这个字符串,再从当前字母后一个位置开始往后再遍历这个数组,即找比当前字母要大的所有字母中编号最大的那个字母的编号

因为相同颜色彼此不能交换,所以同一种颜色组成的序列绝对是非严格递增的

基于这个结论,顺序遍历字符串时,假设在涂颜色编号为1的字符

如果遇到一个字符比前面最大的涂了编号1颜色的字符小,为了不破坏非严格递增的条件,就必须把他涂作编号2

如果遇到一个字符比前面最大的涂了编号1和编号2颜色的字符都小,为了不破坏非严格递增的条件,就必须把他涂作编号3

以此类推可以得到,假设遍历到某个字符时,前面比这个字符大的字符中涂过的颜色编号最大为 d

那么 1~d 的所有颜色都已经出现在比这个字符大的字符上

又因为要让这个字符往前移动到它应该在的位置,那么它的颜色就一定要不同于所有的比它大的字符出现过的所有颜色

所以就可以得出结论,每次找比当前字母大的所有字母中涂色方案最大的编号+1,即为当前字母涂色方案

代码如下

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 void solve(){
 4     int n,i,j,d,r[26]={0},ans2=1;
 5     string s;
 6     cin>>n>>s;
 7     vector<int> ans;
 8     for(i=0;i<n;i++){
 9         d=1;
10         for(j=s[i]-‘a‘+1;j<26;j++)
11             d=max(d,r[j]+1);
12         r[s[i]-‘a‘]=d;
13         ans.emplace_back(d);
14         ans2=max(ans2,d);
15     }
16     cout<<ans2<<‘\n‘<<ans[0];
17     for(i=1;i<n;i++)
18         cout<<‘ ‘<<ans[i];
19 }
20 int main(){
21     ios::sync_with_stdio(0);
22     cin.tie(0);cout.tie(0);
23     solve();
24
25     return 0;
26 }

解题思路 2:

其实根据easy版本就能猜到

涂0颜色的是非严格递增的

涂1颜色的也是非严格递增的

其实这也是上面的结论

因为相同颜色彼此不能交换,所以必定是已经有顺序的

那么就可以得到这一种想法,编号从1开始,从头到尾遍历出一条非严格递增的标记为颜色1,如果标记出来的数量和小于n(即还有一些字符没有被标记),那么就加一种颜色,重新再来一遍,以此循环,直到所有字符都被标记上了颜色

实测方案可行,代码如下

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 void solve(){
 4     int n,i,done=0,cur=0;
 5     char mx;
 6     string s;
 7     cin>>n>>s;
 8     vector<int> ans(n,0);
 9     while(done<n){
10         mx=‘a‘;
11         cur++;
12         for(i=0;i<n;i++){
13             if(!ans[i]&&s[i]>=mx){
14                 mx=s[i];
15                 done++;
16                 ans[i]=cur;
17             }
18         }
19     }
20     cout<<cur<<‘\n‘<<ans[0];
21     for(i=1;i<n;i++)
22         cout<<‘ ‘<<ans[i];
23 }
24 int main(){
25     ios::sync_with_stdio(0);
26     cin.tie(0);cout.tie(0);
27     solve();
28
29     return 0;
30 }

原文地址:https://www.cnblogs.com/stelayuri/p/12262365.html

时间: 2024-07-30 14:09:50

Codeforces 1296E2 - String Coloring (hard version)的相关文章

String Coloring (hard version)

E2. String Coloring (hard version) 首先我们要明确一点,最多只会出现26种颜色,因为当下字母s[i]如果在后面s[>i]出现过,那么在 i 这个位置的最佳颜色选择即为先前确定的颜色.所以我们可以使用状态压缩来记录状态. // Created by CAD on 2020/2/5. #include <bits/stdc++.h> using namespace std; int a[200005]; int x[27]; int main() { ios

CF1296E2 String Coloring (hard version)

欢迎来看看呀 题目大意:给你一串长度为n的字符串,你可以给每个位置上染上一种不大于n的颜色,对于相邻的两个位置,如果他们的颜色不同则可以交换他们的位置,现在需要交换若干次后按照字典序排序,你需要找到最少满足条件的颜色数并输出方案 可以想到,只有一个字符要与另一个字符交换,才要染成不同颜色,从前往后来考虑,我们只用考虑一个字符与在它前面的字符交换就行了,因为枚举到后面需要与其交换的字符,自然会考虑到它 只有比它大的字符才会跟它交换,所以我们只需要让它与比它大的字符不同颜色即可 然后要想到这样的一个

CodeForces 159c String Manipulation 1.0

String Manipulation 1.0 Time Limit: 3000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Original ID: 159C64-bit integer IO format: %I64d      Java class name: (Any) One popular website developed an unusual username editing proced

Codeforces 118A String Task

题目链接 http://codeforces.com/problemset/problem/118/A #include<iostream> #include<string> #include<cctype> #include<algorithm> using namespace std; int main() { string str; cin>>str; int i; //将代码变成小写 transform(str.begin(), str.

Codeforces C - String Reconstruction

C - String Reconstruction 方法一:把确定的点的父亲节点设为下一个点,这样访问过的点的根节点都是没访问过的点. 代码: #include<bits/stdc++.h> using namespace std; const int N=1e6+5; char s[N],res[N*2]; int fa[N*2]; int Find(int x) { return x==fa[x]?x:fa[x]=Find(fa[x]); } int main() { for(int i=

CodeForces 828C String Reconstruction(并查集思想)

题意:给你n个串,给你每个串在总串中开始的每个位置,问你最小字典序总串. 思路:显然这道题有很多重复填涂的地方,那么这里的时间花费就会特别高. 我们维护一个并查集fa,用fa[i]记录从第i位置开始第一个没填涂的位置,那每次都能跳过涂过的地方.每次填完当前格就去填find(fa[i + 1]). ps:一定要合并,不然超时. 代码: #include<stack> #include<vector> #include<queue> #include<set>

CodeForces 1118F2. Tree Cutting (Hard Version)

题目简述:给定$n \leq 3 \times 10^5$个节点的树,其中一部分节点被染色,一共有$k$种不同的颜色.求将树划分成 $k$ 个不相交的部分的方案数,使得每个部分中除了未染色的节点以外的所有节点颜色相同,答案模$998244353$(质数). 解:code Step 1. 缩点 相关题目:CodeForces 76F. Tourist 观察:为使相同颜色的节点处在同一个子树中,则包含这些节点的最小子树的所有节点必然会被划分在同一部分. 因此,在随意选择一个节点作为树的根节点后,每种

codeforces#1290E2 - Rotate Columns (hard version)(子集dp)

题目链接: https://codeforces.com/contest/1209/problem/E2 题意: 给出$n$行和$m$列 每次操作循环挪动某列一次 可以执行无数次这样的操作 让每行最大值的累加和最大 数据范围: $1\leq n \leq 12$ $1\leq m \leq 20000$ 分析: 定义$dp[i][j]$,考虑前$i$列,选择状态为$j$的最大值 $ans=dp[m][(1<<n)-1]$ $dp[i][j]$可以由$dp[i-1][k]$转移,$k$是$j$的

codeforces - 1249B2 Books Exchange (hard version)

https://vjudge.net/problem/CodeForces-1249B2 题目描述: The only difference between easy and hard versions is constraints. There are nn kids, each of them is reading a unique book. At the end of any day, the ii-th kid will give his book to the pipi-th kid