LOJ #3217. 「PA 2019」Desant(状压dp)

https://loj.ac/problem/3217

考虑已经确定了前i个,状态可以只记后面的\(n-i\)个点之间的\(n-i+1\)个间隔里的已选的数。

这个状态最大是\(\sum_{k=1}^n (n/k)^k\)左右,可以发现不是很大。

注意要用多进制数去存状态,不然会被卡常。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 45;

int n, a[N];

int b[N], b0;

struct nod {
	ll w0, w[N];
} p, q;

void build(int *b, int &b0, nod &p) {
	sort(b + 1, b + b0 + 1);
	b[0] = 0; b[b0 + 1] = n + 1;
	p.w0 = b0;
	p.w[0] = 1;
	fo(j, 1, b0 + 1) p.w[j] = p.w[j - 1] * (b[j] - b[j - 1]);
}

void zh(int *a, nod b, int x) {
	fo(i, 0, b.w0) a[i] = x % b.w[i + 1] / b.w[i];
}

int zy(int *a, nod b) {
	int s = 0;
	fo(i, 0, b.w0) s += a[i] * b.w[i];
	return s;
}

struct P {
	int x; ll y;
	P(int _x = 0, ll _y = 0) {
		x = _x, y = _y;
	}
};

P operator + (P a, P b) {
	return a.x == b.x ? P(a.x, a.y + b.y) : (a.x < b.x ? a : b);
}

vector<P> f[N];

int main() {
	freopen("a.in", "r", stdin);
	scanf("%d", &n);
	fo(i, 1, n) scanf("%d", &a[i]);
	
	f[0].resize(1);
	f[0][0] = P(0, 1);
	
	fo(i, 0, n - 1) {
		b0 = 0;
		fo(j, i + 1, n) b[++ b0] = a[j];
		build(b, b0, p);
		int id; fo(j, 1, b0) if(b[j] == a[i + 1]) id = j;
			
		b0 = 0;
		fo(j, i + 2, n)	b[++ b0] = a[j];
		build(b, b0, q);
		
		int m1 = p.w[p.w0 + 1], m2 = q.w[q.w0 + 1];
		
		f[i + 1].resize(m2);
		ff(k, 0, m2) f[i + 1][k] = P(1e9, 0);
		
		ff(k, 0, m1) if(f[i][k].y) {
			static int c[N], d[N];
			zh(c, p, k);
			fo(cho, 0, 1) {
				P v = f[i][k];
				if(cho) {
					fo(u, id, p.w0) v.x += c[u];
				}
				int t = -1;
				fo(u, 0, p.w0) {
					if(u == id) {
						d[t] += c[u] + cho;
					} else d[++ t] = c[u];
				}
				int nk = zy(d, q);
				f[i + 1][nk] = f[i + 1][nk] + v;
			}
		}
	}

	static P ans[N];
	fo(i, 1, n) ans[i] = P(1e9, 0);	
	ff(k, 0, f[n].size()) {
		static int c[N];
		zh(c, q, k);
		int x = 0;
		fo(u, 0, q.w0) x += c[u];
		ans[x] = ans[x] + f[n][k];
	}
	fo(i, 1, n) pp("%d %lld\n", ans[i].x, ans[i].y);
}
posted @ 2020-05-30 10:38  Cold_Chair  阅读(682)  评论(0编辑  收藏  举报