Prime Permutation
原题地址: http://codeforces.com/problemset/problem/123/A
题目大意:
给你一个字符串(只包含小写字母),从1开始存放。定义长度为|s|,有1<=|s|<=1000。要求通过调整字符在字符串中的位置,使得: 设p为小于等于|s|的素数,有s[p]=s[p*i] (p*i<=|s|),能够完成该项任务就输出YES和调整后的字符串,不能则输出NO。
大致思路:
由于s[p]=s[p*i],如果|s|足够大,便有: s[2]=s[4]=s[6]=s[8]… s[3]=s[6]=s[9]… s[5]=s[10]…
所以s[3]=s[6]=s[2]=s[10]=s[5],也就是当|s|增大时,就把前面的素数连在一起,所以要求给定的数组中绝大部分的字符应该是一样的,所以我们可以定义一个变量mt,用来记录最大的出现次数,如果mt小于某个值,就输出NO,大于就输出YES。现在的任务就是求出对应字符串长度的这个值,很明显|s+1|的对应值可以由|s|的对应值求来。
现在我们定义一个数组dp[1010],dp[i]记录长度为i的字符串重复字符的最少个数。比如: aabbb 长度为5,有s[2]=s[4],所以dp[5]=2,显然,该字符串可以输出YES。
可以想见: 如果i+1是一个素数,那么dp[i+1]=dp[i],如果i+1不是素数,有dp[i+1]=dp[i]+1;但单单这样是不准确的,因为比如dp[5]=2,5+1不是一个素数,但它的出现不仅影响到本身:s[2]=s[6],还通过s[3]=s[6]影响到3,所以实际上dp[6]=4,即2、3、4、6四位应该是相同的。也就是每当到一定的长度,总会把一些底层素数连在一起,到6时就把2、3连在一起,到10就把2、5连在一起,到14就把2、7连在一起,于是我们可以初始化dp[i*2]=1,i为素数。
AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 #define Max 1010 4 int main() 5 { 6 int pri[Max]; //pri[i]两个状态 1表示是素数,0表示不是素数,注意,c里面初始化为1不能直接在定义中进行 7 int dp[Max]={0}; //dp[i]记录长度为 i 的字符串重复字符的最少个数 8 int a[26]; //26个字符各自出现次数 9 int mt,ls,i,j,ll; 10 char mi; 11 char s[Max],ss[Max]; 12 for(i=0;i<Max;i++) 13 pri[i]=1; 14 pri[0]=pri[1]=0; 15 dp[0]=dp[1]=1; 16 for(i=2;i<Max;i++) 17 { 18 if(pri[i]) 19 { 20 if(i*2<Max) 21 dp[i*2]=1; 22 for(j=2*i;j<Max;j+=i) 23 pri[j]=0; 24 } 25 } 26 dp[4]=0; //经过上面的初始化,dp[4]由于2*2也变成了1,但4并没有连接两个素数,所以取消 27 for(i=2;i<Max;i++) 28 { 29 if(pri[i]) 30 dp[i]+=dp[i-1]; 31 else 32 dp[i]+=dp[i-1]+1; 33 } 34 s[0]=‘0‘; 35 while(scanf("%s",s+1)!=EOF) 36 { 37 ls=strlen(s); 38 for(i=0;i<26;i++) 39 a[i]=0; 40 for(i=1;i<ls;i++) 41 a[s[i]-‘a‘]++; 42 for(mt=0,i=0;i<26;i++) 43 if(a[i]>mt) 44 { 45 mt=a[i]; 46 mi=i+‘a‘; 47 } 48 if(mt>=dp[ls-1]) 49 { 50 printf("YES\n"); 51 for(ll=0,i=1;i<ls;i++) 52 if(s[i]!=mi) ss[ll++]=s[i]; //将s中不是出现最多次的字符存起来 53 for(i=1;i<ls;i++) 54 if(i>1&&(pri[i]==0||i*2<ls)) 55 { 56 s[i]=mi; //必须是相同字符的位置放上出现次数最多的字符 57 mt--; //放上一个就消耗一个mi 58 } 59 for(i=1;i<ls;i++) 60 if(i<=1||pri[i]&&i*2>=ls) 61 { 62 if(mt>0) 63 { 64 mt--; //将还没完的mi消耗完 65 s[i]=mi; 66 } 67 else 68 { 69 s[i]=ss[--ll]; //用其他字符填充空缺 70 } 71 } 72 printf("%s\n",s+1); 73 } 74 else 75 printf("NO\n"); 76 } 77 return 0; 78 }