codeforces 123A A. Prime Permutation(数论+构造)

题目链接:

codeforces 123A


题目大意:

给出一个字符串,问能否通过打乱它的顺序得到一个新的字符串,这个字符串满足所有的质数位和位数是这个质数的倍数的位数上的字母相同,输出能否,如果能,构造一组解.


题目分析:

  • 首先我们知道输入的字符串的字母的顺序无所谓,我们只需要记录每个字母出现的次数。
  • 然后我们发现不管n是多少,集合的形式一定是一个大集合,和一些规模为1的小集合,且这些集合的元素是质数,且大集合不存在这个质数的倍数。这个很显然。
  • 利用上面的结论,我们只需要找到大集合的规模,然后看是否存在一个字母的数量不小于这个大集合的规模,如果存在,那么显然有解。否则无解。
  • 构造最终的解,只需要用找出的字母构造大集合中每个位置的字母,其他的随意即可。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define MAX 1007

using namespace std;
char s[MAX];
int maxPrime[MAX];
int mark[MAX];
int num[30];

void init ()
{
    memset ( maxPrime , -1 , sizeof ( maxPrime ) );
    for ( int i = 2 ; i < MAX ; i++ )
    {
        if (~maxPrime[i]) continue;
        for ( int j = i*2 ; j < MAX ; j += i )
            maxPrime[j] = i;
    }
}

int main ( )
{
    init ();
    while (~scanf ( "%s" , s ) )
    {
        int n = strlen ( s );
        memset ( mark , 0 , sizeof ( mark ) );
        if ( n < 4 )
        {
            puts ( "YES" );
            puts ( s );
            continue;
        }
        int cnt = 2;
        for ( int i = n ; i >= 2; i-- )
        {
            if ( mark[i] && maxPrime[i] == -1 ) continue;
            if ( ~maxPrime[i] )
            {
                mark[i] = true;
                for ( int j = 2 ; j*j <= i ; j++ )
                {
                    if ( i%j ) continue;
                    mark[j] = mark[i/j] = true;
                }
            }
            else cnt++;
        }
        memset ( num , 0 , sizeof ( num ));
        for ( int i = 0 ; i < n ; i++ )
            num[s[i]-97]++;
        int id = -1;
        for ( int i = 0 ; i < 26 ; i++ )
            if ( n-cnt+1 <= num[i] )
            {
                id = i;
                num[i] -= (n-cnt+1);
                break;
            }
        if ( id == -1 )
        {
            puts ( "NO" );
            continue;
        }
        for ( int i = 0 ; i < n ; i++ )
        {
            if ( mark[i+1] ) s[i] =(char)(id+97);
            else
            for ( int j = 0 ; j < 26 ; j++ )
                if ( num[j] )
                {
                    num[j]--;
                    s[i] = (char)(j+97);
                    break;
                }
        }
        puts ( "YES");
        puts ( s );
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值