CF1430 & Edu96
2025/2/17
链接依然是 luogu 的。
A
丸辣不会 CRT,只会暴力怎么办?
B
显然最小值一定是个空水桶,先把 \(k=0\) 判掉,最大值直接取前 \(k\) 大就可以了。
C
暴力发现答案一定是 \(2\),暴力发现 \(n\to 1\) 倒序删是最优的,形如 \((n-1,n),(n-2,\lceil \dfrac{n-1+n}{2}\rceil)\cdots\),旁边的 Xdik 不知道答案一定是 \(2\) 过了膜拜大佬,好像是用什么优先队列啥的?
D
发现删除操作肯定不能删一个长度为 \(1\) 的连续段,考虑每次暴力找到第一个长度大于 \(1\) 的连续段删一个,这个过程是 \(O(N)\) 的,预处理出连续段长度暴力维护即可。
点击查看
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define pb push_back
#define int long long
using namespace std;
const int N = 2e5 + 5;
int n, m, k, a[N], ret, lst;
char s[N];
void sol() {
cin >> n;
rep(i, 1, n) cin >> s[i];
if(n == 1) return cout << 1 << '\n', void();
lst = 1, ret = m = 0;
rep(i, 2, n) if(s[i] != s[i - 1]) a[++m] = i - lst, lst = i;
a[++m] = n + 1 - lst;
// rep(i, 1, n) cout << a[i] << ' ';
int j = 1;
rep(i, 1, n) {
while(j <= m && a[j] == 1) ++j;
--a[j];
if(j > m) return cout << i - 1 + (m - i + 1 + 1) / 2 << '\n', void();
if(j <= i) j = i + 1;
}
// cout << ret << '\n';
}
signed main() {
FASTIO
int _; cin >> _;
while(_--) sol();
return 0;
}
E
唐题,草稿纸上乱蒙个做法居然是对的,给翻转后的字符串赋个值然后直接冒泡排序求逆序对就做完了。
点击查看
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define pb push_back
#define int long long
using namespace std;
const int N = 2e5 + 5;
namespace BIT {
int tr[N];
#define lowbit(i) (i & -i)
void add(int x, int val) { for(; x < N - 5; x += lowbit(x)) tr[x] += val; }
int ask(int x, int ret = 0) { for(; x; x -= lowbit(x)) ret += tr[x]; return ret; }
void init() { memset(tr, 0, sizeof tr); }
}
int n, m, k, a[N], b[N], ret, lst;
char s[N];
vector<int> vec[26];
void sol() {
ret = 0, BIT::init();
cin >> n;
rep(i, 1, n) cin >> s[i], vec[s[i] - 'a'].pb(i);
reverse(s + 1, s + 1 + n);
rep(i, 1, n) a[i] = vec[s[i] - 'a'][b[s[i] - 'a']++];
pre(i, n, 1) ret += BIT::ask(a[i] - 1), BIT::add(a[i], 1);
cout << ret << '\n';
}
signed main() {
FASTIO
int _; _ = 1;
while(_--) sol();
return 0;
}
F
小清新 dp 题,定义 \(dp_i\) 表示满弹夹进入第 \(i\) 轮的最小代价,然后直接暴力找转移点即可,中途换弹夹什么的都可以暴力算,注意判断找决策点时区间有没有重合,即判断是否有时间换弹夹,啊注意这个 dp 要倒着做。
点击查看
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define pb push_back
#define int long long
#define inf 1e14
using namespace std;
const int N = 2e5 + 5;
namespace BIT {
int tr[N];
#define lowbit(i) (i & -i)
void add(int x, int val) { for(; x < N - 5; x += lowbit(x)) tr[x] += val; }
int ask(int x, int ret = 0) { for(; x; x -= lowbit(x)) ret += tr[x]; return ret; }
void init() { memset(tr, 0, sizeof tr); }
}
int n, m, k, a[N], l[N], r[N], dp[N];
void sol() {
memset(dp, 0x3f, sizeof dp);
cin >> n >> k;
rep(i, 1, n) cin >> l[i] >> r[i] >> a[i];
l[n + 1] = inf;
pre(i, n, 1) {
int cur = k, val = 0;
rep(j, i, n) {
int cnt = (a[j] - cur + k - 1) / k + 1;
if(cnt > r[j] - l[j] + 1) break;
cur = (cur - a[j] % k + k) % k, val += a[j];
if(r[j] < l[j + 1] || cnt < r[j] - l[j] + 1) {
if(j < n) dp[i] = min(dp[i], dp[j + 1] + val + cur);
else dp[i] = min(dp[i], val);
}
}
}
cout << (dp[1] < inf ? dp[1] : -1);
}
signed main() {
FASTIO
int _; _ = 1;
while(_--) sol();
return 0;
}
G
纪念一下 guomao 第一次给我们讲题,讲了 5min 不会讲了 qwq。
分层图 dp 啊,过程用状压实现。
满足对于所有 \((x,y)\in E\),\(x\) 的层数小于 \(y\) 的层数。每层点数相同,层数越大,点权越小,确定分层后就能推出点权。
转移代价
预处理出
- 每个点集 \(S\) 的转移代价。
- 每个点集 \(S\) 的入点集合。
有点小难理解,需要粘一粘代码。
所有代码放博客园里。
点击查看
#include <bits/stdc++.h>
#define rep(i, j, k) for (int i = j; i <= k; ++i)
#define pre(i, j, k) for (int i = j; i >= k; --i)
#define pb push_back
#define inf 0x3fffffff
#define int long long
#define lowbit(i) (i & -i)
using namespace std;
const int N = 19;
int dp[1 << N], s[1 << N], c[1 << N], p[1 << N], num[N], in[N], id[1 << N], idx[1 << N], w[N][N], ans[N];
int n, m, u, v, k;
vector<int> e[N];
void topsort() {
queue<int> q;
rep(i, 0, n - 1) if (!in[i]) q.push(i);
while (q.size()) {
int u = q.front();
q.pop();
for (auto v : e[u]) {
s[v] |= (s[u] | (1 << n));
if (!--in[v])
q.push(v);
}
}
}
void sol(int msk, int x) {
if (!msk)
return;
int pre = p[msk], New = (msk ^ pre);
for (int i = New; i; i -= lowbit(i)) ans[id[lowbit(i)]] = x;
sol(pre, x + 1);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> m;
rep(i, 1, m) {
cin >> u >> v >> k;
w[u][v] = k;
idx[v] |= (1 << u - 1);
}
rep(i, 1, n) id[1 << i - 1] = i;
rep(S, 1, (1 << n) - 1) {
int u = id[lowbit(S)];
int t1 = 0, t2 = 0;
rep(i, 1, n) {
if (S & (1 << i - 1))
t2 += w[i][u];
else
t1 += w[u][i];
}
c[S] = c[S - lowbit(S)] + t1 - t2;
s[S] = (s[S - lowbit(S)] | idx[u]);
}
rep(i, 1, (1 << n) - 1) dp[i] = inf;
// topsort();
rep(S, 0, (1 << n) - 1) {
if (dp[S] == inf)
continue;
int head = (((1 << n) - 1) ^ S);
for (int i = head; i; i = ((i - 1) & head)) {
if ((s[i] & S) ^ s[i])
continue;
if (dp[i + S] > dp[S] + c[S])
dp[S + i] = dp[S] + c[S], p[S + i] = S;
}
}
sol((1 << n) - 1, 1);
rep(i, 1, n) cout << ans[i] << ' ';
return 0;
}

浙公网安备 33010602011771号