题解 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;
}