[贪心][字符串] Jzoj P3207 Orthogonal Anagram

Description

一个字符串的变形词是一个字符串,它含有恰好完全一样的字母,可能以不同的顺序出现。例如,\porter",\report"和\eoprrt"都是\porter"的变形词。而\potter"不是它的变形词,因为\t"和\r"出现的次数不同。

字符串S和T是正交的,当且仅当它们长度相同,而且每个对应位都不同。例如,\card"和\dear"是正交的,而\perk"和\card"不是正交的,因为它们的第3个字母相同。

给出一个字符串S,求S的字典序最小的正交变形词。如果这样的字符串不存在,就让答案是空串。
 

Input

仅一行,一个字符串S。

Output

仅一行,表示答案。
 

Sample Input

abba

Sample Output

baab
 

Data Constraint

有10%数据,字符串长度不超过10。

另有10%数据,恰有2种不同的字母。

另有20%数据,只有不超过5种不同的字母。

对于80%数据,字符串长度不超过50。

对于100%数据,字符串长度不超过50000,所有字符都是小写拉丁字母。

 

题解

  • 我们可以预处理出每个字母出现的次数l[i]和没有出现的次数r[i]
  • 若一个字母出现的次数>没有出现的次数,那么显然这个是没有方案的,因为要满足每一位的字母都不一样,这样的话,就超过n/2个了,显然不能形成
  • 现在来想一下如何用预处理出来的数组来求答案
  • 考虑贪心的思想,要使字典序最小,那么可以放的最小的字母可以先放
  • 那么就枚举放的字母,若l[i]=r[i],也就是说,它占整个字符串的一半,而且我们是按顺序枚举过来的,显然可以放
  • 若没有以上的情况,那么我们就找第一个不等于字符串相对位置,而且是出现过的字母放就好了

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 int l[26],r[26],n;
 5 char s[50010];
 6 int main()
 7 {
 8     scanf("%s",s+1),n=strlen(s+1);
 9     for (int i=1;i<=n;i++) for (int j=0;j<26;j++) if (s[i]==j+97) l[j]++; else r[j]++;
10     for (int i=0;i<26;i++) if (l[i]>r[i]) return 0;
11     for (int i=1;i<=n;i++)
12     {
13         int x=26;
14         for (int j=0;j<26;j++) if (s[i]!=(j+97)&&l[j]==r[j]) x=j;
15         if (x==26) for (int j=0;j<26;j++) if (s[i]!=(j+97)&&l[j]) {x=j; break;}
16         printf("%c",x+97),l[x]--;
17         for (int j=0;j<26;j++) if (s[i]!=(j+97)) --r[j];
18     }
19 }

 

posted @ 2019-01-28 21:09  BEYang_Z  阅读(285)  评论(0编辑  收藏  举报