题目描述:
给出N个A,B
寻找一个集合使价值最大
价值即为集合内A的和
如果 i,j属于集合内并且 i >1 j>1 i^k=j(k>1) 则价值需要减去j的B值
题目分析:
每个幂根之间是不会交叉的,我们只需要把每个幂的链挑出来,用二进制去枚举所有的情况即可
题目链接:
Ac代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#define int long long
const int maxm=110000;
int n;
int a[maxm],b[maxm],c[maxm],num[maxm];
bool vis[maxm];
inline bool check(int x,int y)
{
for(int k=x;k<=y;k*=x)
if(k==y) return 1;
return 0;
}
inline int solve(int cnt)
{
int ans=0;
for(int s=0;s<(1<<cnt);s++)
{
int tot=0,sum=0;
for(int i=1;i<=cnt;i++)
if((1<<(i-1))&s) num[++tot]=c[i],sum+=a[c[i]];
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
if(num[j]<num[i]&&check(num[j],num[i])) sum-=b[num[i]];
ans=std::max(ans,sum);
}
return ans;
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
int ans=a[1];
for(int i=2;i<=n;i++)
if(!vis[i])
{
int cnt=0;
for(int j=i;j<=n;j*=i)
c[++cnt]=j,vis[j]=1;
ans+=solve(cnt);
}
printf("%lld\n",ans);
return 0;
}