【NowCoder】牛客周赛 Round 108 EF (背包问题 | SOSDP)
E.小苯的有趣数
题目:
思路:
转换
考虑到一个显然的结论,1 是有趣的,那么显然答案最少都能为 n - 1,现在考虑是否答案能否变成 n 即可
如何考虑呢?我们参考背包问题的思路,我们将 sum 分为 n 个有趣的数转化为 用 n 个有趣的数能不能组成 sum
所以考虑预处理出所有有趣的数,由于题目数据很小,最大有趣数不超过 100*200,所以可过
最后我们 O(1) 查询即可
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());//用 i 个神秘数 凑出 j
int f[105][200005];void init()
{memset(f,0,sizeof f);f[0][0] = 1;vector<int> v;auto check = [&](int x)->int{int now = 0;while(x) now += x %10,x/=10;return (sqrt(now) * sqrt(now) == now);};for (int i = 1; i <= 200; i++){int j = i*i;if(check(j))v.push_back(j);}for (int i = 1; i <= 100; i++){for(auto & x : v){for(int j = x;j <= 20000;j++){f[i][j] |= f[i-1][j-x];}}}
}void solve()
{int n, x, s=0;cin >> n;for (int i = 0; i < n; i++){cin >> x;s += x;}cout << n - 1 + f[n][s] << endl;
}signed main()
{init();ios::sync_with_stdio(false);cin.tie(nullptr);int t = 1;cin >> t;while (t--){solve();}return 0;
}
F.AND VS MEX
题目:
思路:
一眼
不难发现,如果我们要利用已知的数组 a 且从中选出 k 个数 AND 后成一个数 x,那么我们只能选 x 的超集
那么不难想到SOSDP来计算 x 的超集,由于 x 的 超集 的 AND和 y 一定大于等于 x,即 y >= x,且每次AND上一个数一定是不会更优的,即只会越来越小,所以上诉思路是可行的,考虑如何实现
我们定义 dp[i] 是 i 的所有超集的能组成的最小 AND 和,那么初始化所有 dp[i] 为一个大数,对于存在的 a[i] 显然 dp[a[i]] = a[i],同时题目告诉我们可以加入 0,所以还有 dp[0] = 0
接下来直接按照 SOSDP 板子转移即可,最后直接枚举 MEX,如果 dp[i] != i,那么就说明我们不能构造出 i,此时输出即可
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());void solve()
{int n;cin >> n;vector<int> a(n);int wei = log2(n) + 1;int mx = (1 << wei);vector<int> dp(mx+1,mx - 1);for (int i = 0; i < n; i++){cin >> a[i];dp[a[i]]= a[i];}dp[0] = 0;for (int i = 0; i < wei; i++){for (int j = 0; j < mx; j++){if(!(j >> i & 1)){dp[j] &= dp[j ^ (1 << i)];}}}for (int i = 0; i <= mx; i++){if(dp[i] != i){cout << i << endl;return;}}
}signed main()
{ios::sync_with_stdio(false);cin.tie(nullptr);int t = 1;cin >> t;while (t--){solve();}return 0;
}