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\) 的层数。每层点数相同,层数越大,点权越小,确定分层后就能推出点权。

转移代价

$$\sum\limits_{\forall (u,v)\in E,u\in S,v\notin S} w_{u,v}$$

预处理出

  • 每个点集 \(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;
}
posted @ 2025-02-17 16:58  Iron_Spade  阅读(8)  评论(0)    收藏  举报