朝花夕拾(名字太短)
不定时更新,一些杂题
B. Add 0 or K
https://codeforces.com/problemset/problem/2134/B
题意:
给定一个数组,使整个数组的gcd大于1,每次可以加0或者加k,最后输出整个数组。
解题思路:
要想gcd>1,就要满足以下任意一个条件:
1.有共同的质因数
2.两个数能够相互整除
3.模某个数同余0
这题有一个非常简单的思想,要让 gcd>1,一个常见思路是让所有数在模 m 下同余,这样它们的差是 m 的倍数,从而 gcd 至少是 m 的一个因子(若 m>1)。
那么这个数该怎么选呢?
首先我们要想在这个数据范围下,我们不可能再去进行多次调整,这很容易超时。我们尽可能要一步到位。
选择 M = K + 1 M=K+1 M=K+1
1.由同余定理可得 𝑘 ≡ − 1 ( m o d 𝑘 + 1 ) 𝑘≡−1(mod𝑘+1) k≡−1(modk+1)
所以 a i + t i ∗ k ≡ a i − t i ( m o d k + 1 ) a_i+t_i *k≡a_i−t_i(modk+1) ai+ti∗k≡ai−ti(modk+1)
tips:实在想不到建议guess。
完整代码:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;void solve()
{ll n,k;cin>>n>>k;vector<ll>a(n);for(int i=0;i<n;i++){cin>>a[i];a[i]+=(a[i]%(k+1))*k;}for(int i=0;i<n;i++)cout<<a[i]<<" ";cout<<endl;}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
洛谷 P13957 [ICPC 2023 Nanjing R] 背包
思路:
01背包+免费拿k个物品
我们不能先跑01,再贪心拿,反过来也如此。我们要在跑背包时就要拿免费的。于是,我们就要对免费的东西进行预处理。
我们首先对宝石按它们的价格升序排序,然后枚举用钱买的宝石中的最大值 x,对于小于等于 x 的宝石,我们就跑正常背包,对于大于 x 的宝石,我们就通过贪心选前 k 大的,对两者加起来的值取最大即可。
代码:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;void solve() {int n, W, k;cin >> n >> W >> k;vector<pair<ll, ll>> a(n + 1); // first: w, second: vfor (int i = 1; i <= n; i++) cin >> a[i].first >> a[i].second;sort(a.begin() + 1, a.end());vector<ll> sum(n + 2, 0);vector<int> tmp;//如果购买前 i-1 个物品,可以免费获得后面物品中价值最大的 k 个for (int i = n; i >= 1; i--) {tmp.push_back(a[i].second);sort(tmp.begin(), tmp.end(), greater<int>());ll s = 0;//可以看作是一个后缀最大K和(K个数之和)for (int j = 0; j < min((int)tmp.size(), k); j++) {s += tmp[j];}sum[i] = s;}vector<ll> f(W + 1, 0);ll ans = 0;for (int i = 1; i <= n; i++) {for (int j = W; j >= a[i].first; j--) {f[j] = max(f[j], f[j - a[i].first] + a[i].second);}ans = max(ans, f[W] + sum[i + 1]);}cout << ans << endl;
}int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t = 1;// cin >> t;while (t--) {solve();}return 0;
}
