C1-k-LCM (easy version)
分情况讨论一下
void solve(){
if(n & 1){
cout << 1 << " " << (n / 2) << " " << (n / 2) << '
';
}
else if(n % 4 == 0){
cout << (n / 2) << " " << (n / 4) << " " << (n / 4) << '
';
}
else{
cout << 2 << " " << ((n - 2) / 2) << " " << ((n - 2) / 2) << '
';
}
}
C2-k-LCM (hard version)
转化成C1
void solve() {
for(int i = 1;i <= k - 3;i++){
cout << 1 << " ";n--;
}
if (n & 1) {
cout << 1 << " " << (n / 2) << " " << (n / 2) << '
';
}
else if (n % 4 == 0) {
cout << (n / 2) << " " << (n / 4) << " " << (n / 4) << '
';
}
else {
cout << 2 << " " << ((n - 2) / 2) << " " << ((n - 2) / 2) << '
';
}
}
D-Genius
看完官方的题解感觉挺巧妙的, 设 (f[i]) 表示以 (i) 为终点的最大得分值, 则把边按照从小到大的顺序来枚举,进行转移即可
for(int i = 2;i <= n;i++){
for(int j = i - 1;j >= 1;j--){
}
}
这样的枚举顺序可以保证边权 ((abs(c_i - c_j))) 严格递增
void solve() {
vector<ll>f;
f.resize(n + 1, 0);
for (int i = 2;i <= n;i++) {
for (int j = i - 1;j >= 1;j--) {
ll fi = f[i], fj = f[j], p = abs(s[i] - s[j]);
if (tag[i] != tag[j]) {
f[i] = max(f[i], fj + p);
f[j] = max(f[j], fi + p);
}
}
}
cout << *max_element(f.begin(), f.end()) << '
';
}
E1-Square-free division (easy version)
直接质因数分解然后次数全部模 2 ,转化为分成尽可能少的区间, 使得所有区间内的数两两各不相同,扫一遍就可以
E-2Square-free division (hard version)
设 (f[i][j]) 表示前 (i) 个数,使用了 (j) 次转变的最小段数, 设 (L[i][j]) 表示前 (i) 个数中, (i) 所属的段使用了 (j) 次转变所能到达的最左边的下标, 即 ([L[i][j], i]) 这个段使用了 (j) 次转变,且无法继续向左延申
处理 (L) 的时候可以 (O(nk)) 处理出来, 枚举 (k) ,然后扫一遍。
转移的时候
for (int i = 1;i <= n;i++) {
for (int j = 0;j <= k;j++) {
if (j > 0)f[i][j] = f[i][j - 1];
for (int lst = 0;lst <= j;lst++) {
f[i][j] = min(f[i][j], f[L[i][lst] - 1][j - lst] + 1);
}
}
}
#include<bits/stdc++.h>
using namespace std;
#define what(x) cerr << #x << " is " << x << endl;
#define getall(x,ed) cerr << #x << ": ";debug(x,ed);
#define IO ios::sync_with_stdio(0);cin.tie(0);
std::mt19937 rnd(time(0));
template<typename T>
void debug(T begin, T ed) {
for (T i = begin;i != ed;i++)cout << *i << ' ';cout << '
';
}
const int N = 1e7 + 10;
typedef long long ll;
vector<int>prime, vis, fp, A;
void init() {
vis.resize(N, 0);fp.resize(N, 0);
for (int i = 2;i < N;i++) {
if (!vis[i]) {
prime.emplace_back(i);
fp[i] = i;
}
for (auto& p : prime) {
if (i * p >= N)break;
vis[p * i] = 1;
fp[p * i] = p;
if (i % p == 0)break;
}
}
}
int T, n, k;
void read_and_init() {
cin >> n >> k;
A.resize(n + 1, 0);
for (int i = 1;i <= n;i++) {
int x;cin >> x;
A[i] = 1;
while (x != 1) {
int p = fp[x];
x /= p;
if (fp[x] == p) {
x /= p;
}
else {
A[i] *= p;
}
}
//cout << A[i] << '
';
}
}
unordered_map<int, int>cnt;
void solve() {
vector<vector<int>>f(n + 1, vector<int>(k + 1, 1e9));
vector<vector<int>>L(n + 1, vector<int>(k + 1, 0));
for (int j = 0;j <= k;j++) {
int now = 0;
int idx = 1;
cnt.clear();
for (int i = 1;i <= n;i++) {
if (cnt.count(A[i]))now++;
cnt[A[i]]++;
//cout << i << " " << now << " " << idx << '
';
//for(auto&x : cnt)cout << x.first << " : " << x.second << '
';
if (now <= j)L[i][j] = idx;
else {
while (idx <= i and now > j) {
if (cnt[A[idx]] >= 2)now--;
if (!--cnt[A[idx]])cnt.erase(A[idx]);
idx++;
}
L[i][j] = idx;
}
//what(L[i][j]);
}
}
for (auto& c : f[0])c = 0;
for (int i = 1;i <= n;i++) {
for (int j = 0;j <= k;j++) {
if (j > 0)f[i][j] = f[i][j - 1];
for (int lst = 0;lst <= j;lst++) {
f[i][j] = min(f[i][j], f[L[i][lst] - 1][j - lst] + 1);
}
}
}
cout << f[n][k] << '
';
}
int main() {
IO;
init();
cin >> T;
while (T--) {
read_and_init();
solve();
}
}