题目大意:
有一个集合A={1,2....n},从A中选出一个子集,在这个子集中 初始权值为 ,对于任意的i>=2,j>=2,如果有
,那么这个子集的权值就要减去
。
题目思路
嗯..刚开始思路是对的..
第一步:可以确定我们可以按幂去分组,因为2的幂与3的幂集合之间没有任何的交集,也就是说,如果已经把2选入到子集中,那么3选进去与3不选进去是没有影响的。能产生的影响的只有 底数相同的幂。
第二步:我们按幂分组之后,组内的数就被确定,之后我们就需要枚举组内的数可以产生的组合,然后分别去修改这些组合,使得这些组合满足题目中的条件。最后计算当前这种组合的权值,作为这个子集这时的权值,枚举所有组合的权值之后取一个最大值,即为幂分组后该组对答案的贡献。
第三步:如何计算出当前这个组合的权值呢?题目中说只要出现一对(i,j)满足那么bj就要减去一次,所以我们首先令当前组合的ai全部加入,第一层for循环枚举x,第二层for循环枚举y是不是x的幂。如果是的话就减去一次:
ll judge(ll x,ll y) { for(ll k=x;k<=n;k*=x) if(k==y) return 1; return 0; } //以上为judge函数,判断y是否为x的幂。 for(ll k=1;k<=x;k++) { if(i>>(k-1)&1)//第k位是否为1 c[++cot]=save[k]; } for(ll k=1;k<=cot;k++) sum+=a[c[k]]; for(ll k=1;k<=cot;k++) { for(ll j=1;j<=cot;j++) { if(c[j]<c[k]&&judge(c[j],c[k])) sum-=b[c[k]]; } }第四步: 计算一下时间复杂度,因为二进制枚举的时间复杂度为:
,指数级别的复杂度是很令人害怕的,开始我也没敢写,不过计算一下这个复杂度:按幂分组之后,组中元素个数最多为
,也就是最坏的二进制枚举为
,然后外层套一个sqrt(N),因为sqrt(N)之后的,要么已经被幂分组分进去了,要么没有被幂分组分进去,此时这个数可以直接加入到这个子集里。所以总体的时间复杂度为:
,由于n是100000大概是个1e7~5e7的复杂度,但是绝对比这个复杂度要小很多,因为计算的最坏情况!
所以剩下的内容就看你的二进制枚举学的怎么样了,其实感觉挺简单的,开始M题意读错了,唉.. 放一下代码啦
hhaha 牛哥会在阿楚姐的帮助下送我抱枕嘛?
ll n,m,p;
ll a[maxn],b[maxn],c[maxn];
ll vis[maxn];
ll save[maxn];
ll judge(ll x,ll y)
{
for(ll k=x;k<=n;k*=x)
if(k==y) return 1;
return 0;
}
ll work(ll x)
{
ll maxl=0;
for(ll i=0;i<(1<<x);i++)
{
ll cot=0;
ll sum=0;
for(ll k=1;k<=x;k++)
{
if(i>>(k-1)&1)//第k位是否为1
c[++cot]=save[k];
}
for(ll k=1;k<=cot;k++) sum+=a[c[k]];
for(ll k=1;k<=cot;k++)
{
for(ll j=1;j<=cot;j++)
{
if(c[j]<c[k]&&judge(c[j],c[k]))
sum-=b[c[k]];
}
}
maxl=max(sum,maxl);
}
return maxl;
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
ll res=a[1];
for(ll i=2;i*i<=n;i++)
if(!vis[i])
{
for(ll k=i*i;k<=n;k*=i)
vis[k]=1;
}
for(ll i=2;i<=n;i++)
{
ll cnt=0;
if(i*i<=n&&!vis[i])
{
for(ll k=i;k<=n;k*=i) save[++cnt]=k;
res+=work(cnt);
}
else if(i*i>n&&!vis[i]) res+=a[i];
}
printf("%lld\n",res);
return 0;
}

京公网安备 11010502036488号