POJ - 1777 Vivian's Problem 梅森素数+状压dp

本文介绍了一种利用梅森素数和状态压缩动态规划解决特定数学问题的方法。该问题要求判断是否存在一组指数使得给定数值的因子和为2的幂,并找到最大可能的指数组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:给出K个数,p1,p2,……pk,不一定是素数,给这些数添加指数,0-10之间,最终的乘积为n,他的所有因子和为m,问是否存在一个m为2的幂,如果有多个输出最大的指数,如果没有输出NO。

思路:

如果p是一个素数,并且m=2^p-1也是素数,那么m就称为梅森素数

一个重要的定理:“一个数能够写成几个不重复的梅森素数的乘积” 等价于 “这个数的约数和是2的幂次”N的约数和2幂次是可以直接由构成它的梅森素数的来源2幂次p相加而得到。

在题目给出的范围之内,只有8个梅森素数。状态压缩dp解决

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f

const int maxn=150;
int p[maxn],sta[maxn],dp[1<<8];
int mason[8]={3,7,31,127,8191,131071,524287,2147483647};
int cnt[8]={2,3,5,7,13,17,19,31};
int judge(int n){
    int res=0;
    for(int i=0;i<8;i++){
        if(n%mason[i]==0){
            n/=mason[i];
            res|=(1<<i);
            if(n%mason[i]==0)
                return 0;
        }
    }
    if(n>1) return 0;
    return res;
}
int cal(int sta){
    int res=0;
    for(int i=0;i<8;i++)
        if((sta&(1<<i)))
            res+=cnt[i];
    return res;
}
int main(){

    int N,n;
    while(~scanf("%d",&N)){
        n=0;
        for(int i=0;i<N;i++){
            scanf("%d",&p[i]);
            sta[n]=judge(p[i]);
            if(sta[n]!=0)
                n++;
        }
        if(n==0){
            printf("NO\n");
            continue;
        }
        mm(dp,0);
        dp[0]=1;
        for(int i=0;i<n;i++)
            for(int j=0;j<(1<<8);j++)
                if((j&sta[i])==0)
                    dp[j|sta[i]]|=dp[j];
        int ans=0;
        for(int i=0;i<(1<<8);i++)
            if(dp[i])
                ans=max(ans,cal(i));
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值