ZOJ 2523 —— Number of People(数论,胡搞)

题目:Number of People

题意:N个人平均分成若干组开party,而且D天一个循环(汗,这开到什么时候),一个循环里每天一组的人数必须不一样,现在给出D,求最小的满足题意的N。

如果知道N,其实D就是N的因子的个数,有多少个不同因子就可以有多少次不同的分组。

求因子数的话将N进行质因数分解,N = a1^p1 * a2^p2 * a3^p3 ...,a是质因子,然后因子数=(p1+1)*(p2+1)*(p3+1)*... 

虽然D<10000,但N可能很大,比如D=101,101是质数,所以没得分解,此时最小的N = 2^100,连longlong都爆,预处理这种方案是不可行的。

现在反过来知道D,要求N。按照上面的式子可以想到将D分解成若干个因子得到指数,再将质数分配给质因子就能得到N,但是具体怎么分解最优我就不知道了。。。

比如样例1是分解成最多的个数,而样例2却是分解少的,如果分解成2*2*2得到2^1 * 3^1 * 5^1 = 30,反而更大。

所以我只能采取暴力枚举方案的极端手段了(> < 智商不够了)。

由于每次分解到的因子数并不会太多,所以不用担心暴力的时间。

判断大小我是直接用double乘起来,虽然会丢失一定的精度,但是由于这种指数运算稍微有点不同结果差异挺大的,所以比较还是没什么问题的。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<cmath>
using namespace std;
const int N = 10010;
bool f[N];
int p[N], a[N], b[N], c[N], n, m, k;
double ans;
void dfs(int x){
    if(x==k){
        int L = 0;
        for(int i=0; i<k; i++){
            if(c[i])    b[L++] = c[i]-1;
        }
        sort(b, b+L, greater<int>());
        double cur = 1.0;
        for(int i=0; i<L; i++){
            cur *= pow(p[i]*1.0, b[i]);
        }
        if(cur<ans){
            ans = cur;
            n = L;
            for(int i=0; i<n; i++)  a[i] = b[i];
        }
        return;
    }
    dfs(x+1);
    for(int i=x+1; i<k; i++){
        c[i] *= c[x];
        int tmp = c[x];
        c[x] = 0;
        dfs(x+1);
        c[x] = tmp;
        c[i] /= tmp;
    }
}
int main(){
    m = 0;
    memset(f,0,sizeof(f));
    for(int i=2; i<N; i++){
        if(!f[i]){
            p[m++] = i;
            for(int j=i<<1; j<N; j+=i) f[j]=1;
        }
    }
    int d;
    while(~scanf("%d", &d)){
        k = 0;
        for(int i=0; i<m && d>1; i++){
            if(d%p[i]==0){
                while(d%p[i]==0){
                    d/=p[i];
                    a[k++] = p[i];
                }
            }
        }
        sort(a, a+k, greater<int>());
        ans = 1.0;
        for(int i=0; i<k; i++){
            c[i] = a[i];
            a[i]--;
            ans *= pow(p[i]*1.0, a[i]);
        }
        n = k;
        dfs(0);
        for(int i=0; i<n; i++){
            if(i)   printf(" * ");
            printf("%d^%d", p[i], a[i]);
        }
        puts("");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值