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