题解 card

传送门

\(\frac{n^3}{w}\) 的做法先咕掉了,这个是 \(n^3\)

考虑优化一下 \(n^4\) 的DP
发现上次选的若是第一张,此时第二张一定与第三张相连
而若上次选的是第三张,此时上一张一定与第三张相连
于是可以优化状态
而且发现若最终前三张牌为 \(i, j, k\)
答案可以表示为 \(suf_1-suf_k-v_i-v_j\)
于是只要做可行性DP即可
\(f_{i, j, k}\) 为当前第三张为 \(i\),第一张为 \(j\),第二张为 \(k\),上一张为 \(i-1\) 的状态是否可达
\(g_{i, j, k}\) 为当前第三张为 \(i\),第一张为 \(j\),上一张为 \(k\),第二张为 \(i-1\) 的状态是否可达
选第三张做第一维是因为不管怎么选,第三张牌都恰好下移1位,方便转移
于是依据题意转移即可,注意要做到 \(n+3\) 而不是 \(n\)

这部分 Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 52
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int c[10000], a[10000], v[10000];

namespace task1{
	int dp[N][N][N][N], usiz;
	pair<int, int> uni[N];
	int dfs(int i, int j, int k, int lst) {
		// cout<<"dfs: "<<i<<' '<<j<<' '<<k<<' '<<lst<<endl;
		if (~dp[i][j][k][lst]) return dp[i][j][k][lst];
		if (i>n) return 0;
		int* t=&dp[i][j][k][lst];
		*t=0;
		if (k<=n) {
			if (lst==0) {
				*t=max(*t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
				*t=max(*t, dfs(i, j, k+1, lower_bound(uni+1, uni+usiz+1, make(c[k], a[k]))-uni)+v[k]);
			}
			else {
				int lstc=uni[lst].fir, lsta=uni[lst].sec;
				if ((c[i]==lstc||a[i]==lsta)) *t=max(*t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
				if ((c[k]==lstc||a[k]==lsta)) *t=max(*t, dfs(i, j, k+1, lower_bound(uni+1, uni+usiz+1, make(c[k], a[k]))-uni)+v[k]);
			}
		}
		else {
			if (lst==0) {
				*t=max(*t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
			}
			else {
				int lstc=uni[lst].fir, lsta=uni[lst].sec;
				if ((c[i]==lstc||a[i]==lsta)) *t=max(*t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
			}
		}
		// cout<<"return: "<<(*t)<<endl;
		return *t;
	}
	void solve() {
		// cout<<double(sizeof(dp))/1000/1000<<endl;
		for (int i=1; i<=n; ++i) uni[i]=make(c[i], a[i]);
		sort(uni+1, uni+n+1);
		usiz=unique(uni+1, uni+n+1)-uni-1;
		memset(dp, -1, sizeof(dp));
		printf("%d\n", dfs(1, 2, 3, 0));
		exit(0);
	}
}

namespace task2{
	int usiz;
	pair<int, int> uni[10000];
	struct st{
		pair<pair<pair<int, int>, int>, int> p;
		st(){}
		st(int a, int b, int c, int d){p=make(make(make(a, b), c), d);}
	};
	inline bool operator < (st a, st b) {return a.p<b.p;}
	map<st, int> dp;
	int dfs(int i, int j, int k, int lst) {
		// cout<<"dfs: "<<i<<' '<<j<<' '<<k<<' '<<lst<<endl;
		if (dp.find(st(i, j, k, lst))!=dp.end()) return dp[st(i, j, k, lst)];
		if (i>n) return 0;
		int t=0;
		if (k<=n) {
			if (lst==0) {
				t=max(t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
				t=max(t, dfs(i, j, k+1, lower_bound(uni+1, uni+usiz+1, make(c[k], a[k]))-uni)+v[k]);
			}
			else {
				int lstc=uni[lst].fir, lsta=uni[lst].sec;
				if ((c[i]==lstc||a[i]==lsta)) t=max(t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
				if ((c[k]==lstc||a[k]==lsta)) t=max(t, dfs(i, j, k+1, lower_bound(uni+1, uni+usiz+1, make(c[k], a[k]))-uni)+v[k]);
			}
		}
		else {
			if (lst==0) {
				t=max(t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
			}
			else {
				int lstc=uni[lst].fir, lsta=uni[lst].sec;
				if ((c[i]==lstc||a[i]==lsta)) t=max(t, dfs(j, k, k+1, lower_bound(uni+1, uni+usiz+1, make(c[i], a[i]))-uni)+v[i]);
			}
		}
		// cout<<"return: "<<(*t)<<endl;
		return dp[st(i, j, k, lst)]=t;
	}
	void solve() {
		// cout<<double(sizeof(dp))/1000/1000<<endl;
		for (int i=1; i<=n; ++i) uni[i]=make(c[i], a[i]);
		sort(uni+1, uni+n+1);
		usiz=unique(uni+1, uni+n+1)-uni-1;
		printf("%d\n", dfs(1, 2, 3, 0));
		exit(0);
	}
}

namespace task{
	bool f[510][510][510], g[510][510][510];
	int suf[N], ans;
	bool able(int s, int t) {
		// cout<<"able: "<<s<<' '<<t<<endl;
		if (!s||t>n) return 1;
		else return c[s]==c[t]||a[s]==a[t];
	}
	void solve() {
		g[3][1][0]=1;
		for (int i=n; i; --i) suf[i]=suf[i+1]+v[i];
		for (int i=1; i<=n+3; ++i) {
			for (int j=1; j<i; ++j) {
				for (int k=0; k<j; ++k) if (g[i][j][k]) {
					// cout<<"g: "<<j<<' '<<i-1<<' '<<i<<endl;
					if (able(k, j)) g[i+1][i-1][j]=1;
					if (able(k, i)) f[i+1][j][i-1]=1;
				}
			}
			for (int k=1; k<i; ++k) {
				for (int j=1; j<k; ++j) if (f[i][j][k]) {
					// cout<<"f: "<<j<<' '<<k<<' '<<i<<endl;
					if (able(i-1, j)) g[i+1][k][j]=1;
					if (able(i-1, i)) f[i+1][j][k]=1;
				}
			}
		}
		for (int j=1; j<=n+3; ++j) {
			for (int k=j+1; k<=n+3; ++k) {
				for (int i=k+1; i<=n+3; ++i) if (f[i][j][k]) {
					ans=max(ans, suf[1]-suf[i]-v[j]-v[k]);
				}
			}
		}
		for (int k=0; k<=n+3; ++k) {
			for (int j=k+1; j<=n+3; ++j) {
				for (int i=j+1; i<=n+3; ++i) if (g[i][j][k]) {
					ans=max(ans, suf[1]-suf[i]-v[j]-v[i-1]);
				}
			}
		}
		printf("%d\n", ans);
		exit(0);
	}
}

signed main()
{
	freopen("card.in", "r", stdin);
	freopen("card.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) c[i]=read(), a[i]=read(), v[i]=read();
	// if (n<=50) task1::solve();
	// else task2::solve();
	task::solve();

	return 0;
}
posted @ 2021-11-19 14:52  Administrator-09  阅读(0)  评论(0编辑  收藏  举报