dfs模拟暴力(ecfinal M题)

https://codeforces.com/gym/102471/problem/M

题意:给你集合A of {1,2,,n} , 求子集的最大分数

给出a[1],a[2]...a[n] 和 b[1],b[2]...b[n].

积分规则:

1、初始分数为0.

2、每一个加入集合的i加上a【i】分数

3、集合中任意 (i,j) 满足i≥2, j≥2, i∈A and j∈A, 有 k>1 i的k次方=j, 就减掉b【j】分数。

解法:sqrt(n)个数每个数存在次方关系的下标单拎出来,进行dfs暴力选与不选.

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 100100;
const int M = 1e9+7;
int n,k;
ll a[maxn],b[maxn];
bool vis[maxn];

ll val[maxn],sub[maxn];
bool slt[maxn];         //select
ll mx;

void dfs(int idx,ll sum)
{
    if(idx == k)
    {
        mx = max(mx,sum);
        return;
    }
    slt[idx] = 1;      //选
    ll temp = sum+val[idx];
    for(int i = 1; i < idx; i++)
    {
        if(slt[i] && idx%i == 0) temp -= sub[idx];
    }
    dfs(idx+1,temp);
    slt[idx] = 0;       //回溯,不选
    dfs(idx+1,sum);
}

ll solve(int x)
{
    k = 1;
    for(int i = x; i <= n; i*=x)
    {
        vis[i] = 1;
        val[k] = a[i];
        sub[k] = b[i];
        k++;
    }
    mx = 0;
    //memset(slt , false , sizeof(slt));
    dfs(0,0);
    return mx;
}

int main()
{
/*#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
#endif*/
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld",&a[i]);
    }
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld",&b[i]);
    }
    ll ans = 0;
    for(int i = 2; i <= sqrt(n); i++)
    {
        if(!vis[i])ans += solve(i);//注意不要重复领出来,领一次就可以
    }
    for(int i = 1; i <= n; i++)
    {
        if(!vis[i]) ans += a[i];
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-01-06 14:45  无名菜鸟1  阅读(278)  评论(0编辑  收藏  举报