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;
}

浙公网安备 33010602011771号