Prime Permutation

             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 }
View Code

 

        

 

posted @ 2015-06-18 02:14  hchlqlz  阅读(303)  评论(0编辑  收藏  举报