一道关于梅森素数的题,这里需要先得出一个猜想,那就是只有梅森素数的一次幂的乘积的因子之和才能为2的次幂。这个猜想我不会证明,我只是测了下前100个素数,然后就觉得这个猜想应该是正确的,结果也确实如此。(求数学帝证明)
2^31内仅有8个梅森素数,只要将每个Pi因式分解,直接剔除那些既不是梅森素数,也不是梅森素数乘积的数,注意梅森素数的幂次不能超过1,所以必须选择剩下的可行的数的组合使得到的2的幂次最高,通过一个2维dp很容易得到。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int mersome[8]={3,7,31,127,8191,(1<<17)-1,(1<<19)-1,((1LL)<<31)-1};
int p[8]={2,3,5,7,13,17,19,31};
int st[110],val[110];
int dp[110][1<<10];
int vis[110][1<<10];
int c;
int dfs(int dep,int state)
{
if(dep==c) return 0;
if(vis[dep][state]) return dp[dep][state];
vis[dep][state]=1;
int &ans=dp[dep][state];
ans=dfs(dep+1,state);
if((st[dep]&state)==0) ans=max(ans,dfs(dep+1,state|st[dep])+val[dep]);
return ans;
}
int main()
{
int k;
while(scanf("%d",&k)!=EOF)
{
memset(vis,0,sizeof(vis));
int t;c=0;
for(int i=0;i<k;i++)
{
scanf("%d",&t);
int s=0,v=0;
int flag=1;
for(int j=0;j<8;j++)
{
int tmp=0;
while(t%mersome[j]==0)
{
t/=mersome[j];
tmp++;
}
if(tmp>1) {flag=0;break;}
else if(tmp==1)
{
s^=(1<<j);
v+=p[j];
}
}
if(flag && t==1)
{
st[c]=s;val[c++]=v;
}
}
memset(vis,0,sizeof(vis));
int ans=dfs(0,0);
if(ans<2) puts("NO");
else printf("%d\n",ans);
}
return 0;
}