Loading

PKUWC2024 D1T2 补题记录

加深了一点点对同余最短路的理解。 link

考虑若对所有数 \(+1\),那么 \(f'_{1\dots n}\) 都会 \(+(n - 1)\),这启示我们可以根据最小值划分进行区间 dp。

\(dp_{l, r, V}\) 表示考虑数字 \(f_{l\dots r}\),区间 \(f'_{l\dots r}\) 中已经整体减 \(V\) 还是否能全部减成 \(0\)

每次要么整体减一 \(dp_{l, r, V} \gets dp_{l, r, V - (r - l)}\),要么划分出一个最小值,位置为 \(i(l\le i < r)\),则 \(dp_{l, r, V} \gets dp_{l, i, V} \land dp_{i + 1, r, V}\)

注意对于一个 \(V\)\(r - l\) 的同余系,一定恰好存在一个分界线 \(p\) 满足 \(dp_{l, r, p} = 1\)\(dp_{l, r, p + (r - l)} = 0\),因为我们可以无限地加 \(r - l\)

这启示我们将第三维改为模 \(r - l\) 的余数,即设 \(dp_{l, r, u}\) 表示区间 \([l, r]\) 最多先整体减 \(V\) 合法且 \(V \equiv u \pmod {r - l}\),此时 \(V\) 的最大值。

这题关键在于如何合并 \(dp_{l, i, \_}\)\(dp_{i + 1, r, \_}\) 两部分,枚举在经过了若干次外部整体加以及对 \([l, r]\)\(r - l\) 的操作后,\(V\)\(i - l\) 以及 \(r - i - 1\) 的余数分别为 \(v_1, v_2\),然后 exCRT 求出 \(\le \min(f_{l, i, v_1}, f_{i + 1, r, v_2})\) 且模 \(i - l\)\(v_1\)、模 \(r - i - 1\)\(v_2\) 的最大数。

\(t = \text{lcm}(i - l, r - i - 1)\),我们可以视为现在有个长度为 \(t\) 的环(不难发现左边操作 \(\frac t {r - i - 1}\) 次,右边操作 \(\frac t {i - l}\) 次后两边增量仍然相同)。

现在我们要变模数(将模 \(t\) 变为模 \(r - l\)),可以仿照 论战捆竹竿 的方法变模数。

  • 感觉自己理解得还不是很透彻,以后应该加训同于最短路部分。
点击查看代码
#include <bits/stdc++.h>

namespace Initial {
	#define ll int
	#define ull unsigned long long
	#define fi first
	#define se second
	#define mkp make_pair
	#define pir pair <int, int>
	#define pb push_back
	#define i128 __int128
	using namespace std;
	const ll maxn = 85, inf = 1e9, mod = 1e9 + 7;
	ll power(ll a, ll b = mod - 2) {
		ll s = 1;
		while(b) {
			if(b & 1) s = 1ll * s * a %mod;
			a = 1ll * a * a %mod, b >>= 1;
		} return s;
	}
	template <class T>
	const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	const inline void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	const inline void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;

namespace Read {
	char buf[1 << 22], *p1, *p2;
//	#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
	template <class T>
	const inline void rd(T &x) {
		char ch; bool neg = 0;
		while(!isdigit(ch = getchar()))
			if(ch == '-') neg = 1;
		x = ch - '0';
		while(isdigit(ch = getchar()))
			x = (x << 1) + (x << 3) + ch - '0';
		if(neg) x = -x;
	}
} using Read::rd;

ll n, a[maxn], f[maxn][maxn][maxn], pos[maxn][maxn][maxn], minval[maxn];
ll b[maxn]; long long res[maxn];

void upd(ll *g, ll u1, ll u2) {
	ll z = u1; u1 %= u2; ll k = __gcd(u1, u2);
	for(ll i = 0; i < k; i++)
		for(ll j = i, c = 0; c < 2; j = (j - u1 + u2) % u2, c += (j == i))
			chkmax(b[j], b[(j + u1) % u2] - z);
}

void print(ll l, ll r, ll w) {
	if(l == r) return;
	ll x = r - l, u = w % x;
	if(pos[l][r][u] == l) {
		w = (a[l] - w) / x;
		res[l] += w, res[r] -= w;
		print(l + 1, r, a[l]);
	} else if(pos[l][r][u] == r) {
		w = (a[r] - w) / x;
		res[l] += w, res[r] -= w;
		print(l, r - 1, a[r]);
	} else {
		ll p = pos[l][r][u], c = 0;
		while(f[l][p][w % (p - l)] < w || f[p + 1][r][w % (r - p - 1)] < w)
			w += x, ++c;//, printf("D %d %d %d\n", l, r, w);
		res[l] += c, res[r] -= c;
		print(l, p, w), print(p + 1, r, w);
	}
}

void exgcd(ll a, ll b, ll &x, ll &y) {
	if(!b) { x = 1, y = 0; return; }
	exgcd(b, a % b, x, y);
	ll t = x; x = y;
	y = t - a / b * y;
}

signed main() {
	rd(n);
	for(ll i = 1; i <= n; i++) rd(a[i]);
	if(n == 1) return puts(a[1]? "No" : "Yes"), 0;
	memset(f, 0xcf, sizeof f);
	for(ll l = n; l; l--)
		for(ll r = l + 1; r <= n; r++) {
			ll d = r - l;
			if(r - l == 1) {
				if(a[l] == a[r])
					f[l][r][a[l] % d] = a[l], pos[l][r][a[l] % d] = l;
			} else {
				if(f[l + 1][r][a[l] % (d - 1)] >= a[l])
					f[l][r][a[l] % d] = a[l], pos[l][r][a[l] % d] = l;
				if(f[l][r - 1][a[r] % (d - 1)] >= a[r])
					f[l][r][a[r] % d] = a[r], pos[l][r][a[r] % d] = r;
			}
			for(ll i = l + 1; i < r - 1; i++) {
				ll g = __gcd(i - l, r - i - 1), t = (i - l) * (r - i - 1) / g;
				ll x, y; exgcd(i - l, r - i - 1, x, y);
				memset(b, 0xcf, sizeof b);
				for(ll u = 0; u < i - l; u++)
					for(ll v = 0; v < r - i - 1; v++) {
						if(f[l][i][u] < 0 || f[i + 1][r][v] < 0) continue;
						ll c = v - u; if(c % g) continue;
						ll lim = min(f[l][i][u], f[i + 1][r][v]);
						ll k = x * c / g, w = k * (i - l) + u;
						w = (w % t + t) % t, w += (lim - w) / t * t;
						if(w >= 0 && w <= lim) chkmax(b[w % d], w);
					}
				upd(b, t, r - l);
				for(ll u = 0; u < d; u++)
					if(b[u] > f[l][r][u]) f[l][r][u] = b[u], pos[l][r][u] = i;
			}
		}
	if(f[1][n][0] >= 0) {
		puts("Yes"), print(1, n, 0);
		for(ll i = 1; i < n; i++)
			printf("%lld ", res[i] += res[i - 1]);
	} else puts("No");
	return 0;
}
posted @ 2024-12-19 20:46  Sktn0089  阅读(39)  评论(0)    收藏  举报