The 2019 ICPC Asia-East Continent Final-M value

题目:

Pang believes that one cannot make an omelet without breaking eggs.

For a subset A of {1,2,…,n}, we calculate the score of A as follows:

  1. Initialize the score as 0.
  2. For any i∈A, add ai to the score.
  3. For any pair of integers (i, j) satisfying i≥2, j≥2, i∈A and j∈A, if there exists positive integer k > 1 such that i^k=j, subtract bj​ from the score.


Find the maximum possible score over the choice of A.

输入描述:
The first line contains a single integer n(1≤n≤100000).
The second line contains n integers a1,a2,…,an(1≤ai≤1000000000)
The third line contains n integers b1,b2,…,bn(1≤bi​≤1000000000).

输出描述:
Print a single integer x --- the maximum possible score.

输入1:

4
1 1 1 2
1 1 1 1

输出1:

4

输入2:

4
1 1 1 1
1 1 1 2

输出2:

3

题意:从集合{1,2,,,n}中选出一个子集A。对于任意i>=2,j>=2,如果满足i^k=j,则减掉b[j]。求这个子集的最大值。

思路:先把{ 2,3,,n}按底数分组,2的幂次数为一组,3的幂次数为一组,以此类推,因为只有在同一组中才可能出现i^k=j的情况。然后分组来处理,具体做法是对每一组用二进制枚举所有可以产生的组合,题目要求的是如果满足i^k=j,则减掉b[j],可以先把枚举出来的a[i]全部加起来,把对应的下标记录下来,然后遍历找有没有i^k=j的情况,如果有就减掉b[j]。枚举该组的所有组合能产生的值,再取一个最大值,即为该分组的最大值。求出每一组的最大值最后加起来即为答案。

#include <iostream>

using namespace std;
typedef long long ll;
ll a[100005],b[100005],m[100005],vis[100005]= {0},c[100005],ans1;
int is_mi(ll a,ll b)
{
    for(ll i=a;i<=b;i*=a)
        if(i==b)return 1;
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    int n,k=0;
    cin>>n;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    for(int i=1; i<=n; i++)
        cin>>b[i];
    ans1=a[1];
    for(int i=2; i<=n; i++)
    {
        ll max1=0,ans=0;
        if(!vis[i])
        {
            k=0;
            for(ll j=i; j<=n; j*=i)//按底数分组
            {
                m[k++]=j;
                vis[j]=1;
            }
            for(int h=0; h<(1<<k); h++)//二进制枚举
            {
                ans=0;
                int t=0;
                for(int l=0; l<k; l++)
                {
                    if(h&(1<<l))
                    {
                        ans+=a[m[l]];
                        c[t++]=m[l];
                    }
                }
                for(int x=0; x<t; x++)//减去其中i^k=j的情况
                    for(int y=0; y<t; y++)
                    {
                        if(c[x]>c[y]&&is_mi(c[y],c[x]))
                            ans-=b[c[x]];
                    }
                max1=max(max1,ans);//枚举该组的所有组合后取一个最大值
            }
        }
        ans1+=max1;//所有分组的最大值相加
    }
    cout<<ans1;
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值