一道思维题。
没怎么观察规律,直接按字面意思做的。用并查集将字符相同的位置归类,然后将类数和已出现字符数量比较,如果出现字符数量小于类数则失败。这道题巧了没有复杂的情况比如6 4对4 3 3,否则就错了
网上搜到了更科学的解法:https://blog.csdn.net/weixin_30613433/article/details/95712756
这种题还是要注意找规律啊!
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <cstring>
#include <stdio.h>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <string>
#define MAX 50500
#define INF 0x3f3f3f3f
#define EXP 1e-9
using namespace std;
typedef long long ll;
int pri[MAX];
char s[MAX];
int tree[MAX];
int val[MAX];
struct node{
int id,num;
}lat[30];
int a[MAX];
int out[1200];
priority_queue<node>p,q;
bool operator<(struct node a,struct node b){
return a.num<b.num;
}
int Find(int x){
int r,t=x;
while(tree[t]!=t){
val[tree[t]]+=val[t];
val[t]=0;
t=tree[t];
}
r=t;
t=x;
//printf("%d %d +++\n",r,t);
while(tree[t]!=t){
tree[t]=r;
t=tree[t];
}
return r;
}
int main(){
int tot=1;
memset(a,0,sizeof(a));
memset(lat,0,sizeof(lat));
a[0]=a[1]=1;
for(int i=2;i<=1000;i++){
if(!a[i]){
for(int j=i+i;j<=1000;j+=i){
a[j]=1;
}
}
}
for(int i=0;i<=1000;i++){
tree[i]=i;
val[i]=1;
}
scanf("%s",s);
int len=strlen(s);
for(int i=0;i<len;i++){
lat[s[i]-'a'].num++;
lat[s[i]-'a'].id=s[i]-'a';
}
for(int i=0;i<26;i++){
q.push(lat[i]);
}
for(int i=2;i<=len;i++){
if(a[i])continue;
int l=len/i;
int ra=Find(i),rb;
for(int j=1;j<=l;j++){
rb=Find(i*j);
//printf("i:%d j:%d ra:%d rb:%d ++\n",i,j,ra,rb);
if(rb!=ra){
tree[rb]=ra;
val[ra]+=val[rb];
val[rb]=0;
}
}
}
//printf("--\n");
for(int i=1;i<=len;i++){
//printf("i:%d %d %d ++\n",i,val[i],tree[i]);
if(val[i]){
node a;
a.num=val[i],a.id=i;
p.push(a);
}
}
int flag=1;
while(!p.empty()){
node a=p.top();
p.pop();
node b=q.top();
q.pop();
//printf("a:%d %d b:%d %d\n",a.num,a.id,b.num,b.id);
if(a.num>b.num){
flag=0;
break;
}
b.num-=a.num;
for(int i=1;i<=len;i++){
if(Find(i)==a.id)
out[i]=b.id;
}
q.push(b);
}
if(!flag)printf("NO\n");
else {
printf("YES\n");
for(int i=1;i<=len;i++)
printf("%c",out[i]+'a');
printf("\n");
}
return 0;
}