[JOISC 2014] 邮戳收集 / Collecting Stamps 题解

[JOISC 2014] 邮戳收集 / Collecting Stamps

每个站台有四种移动方式:
1.上行到上行,代价 \(u_i+v_i\)。
2.上行到下行,代价 \(u_i+e_i\)。
3.下行到下行,代价 \(d_i+e_i\)。
4.下行到上行,代价 \(d_i+v_i\)。

因为最初是从 \(0\) 号台到达了上行站台,最后也是从上行站台结束,所以方式 \(2\) 的数量必须等于方式 \(4\) 的数量,且把方式 \(4\) 看作左括号,方式 \(2\) 看作右括号,必须是一个合法的括号序列。(虽然先有方式 \(2\) 再有方式 \(4\),但是方式 \(4\) 的下标在前面,所以就反过来看)。

设 \(f_{i,j}\) 表示当前完成了前 \(i\) 个打卡,还有 \(j\) 个左括号。有转移 \(f_{i,j} \leftarrow f_{i-1,j-1/j+1/j}+cost\),分别对应以上移动方式。注意一个站台可能有多次增加或抵消左括号,所以有 \(f_{i,j} \leftarrow f_{i,j-1/j+1}+cost\)。

每有一个左括号说明这段路被重新经过了两次,则 \(f_{i,j} \leftarrow f_{i,j}+2j\times T\)。

最后答案为 \(f_{n,0}+(n+1)\times T\),加上了最基础的 \(n+1\) 次移动。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,T;
const int N = 3010,inf=1e18;
int u[N],v[N],d[N],e[N],f[N][N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>T;
    for(int i=1;i<=n;i++){
        cin>>u[i]>>v[i]>>d[i]>>e[i];
    }
    memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++){
            f[i][j]=min(f[i][j],f[i-1][j]+u[i]+v[i]);
            if(j>=1)f[i][j]=min(f[i][j],f[i-1][j]+d[i]+e[i]);
        }
        for(int j=1;j<=n;j++){
            f[i][j]=min(f[i][j],f[i-1][j-1]+d[i]+v[i]);
            f[i][j]=min(f[i][j],f[i][j-1]+d[i]+v[i]);
        }
        for(int j=0;j<n;j++){
            f[i][j]=min(f[i][j],f[i-1][j+1]+u[i]+e[i]);
            f[i][j]=min(f[i][j],f[i][j+1]+u[i]+e[i]);
        }
        for(int j=0;j<=n;j++){
            f[i][j]+=2*j*T;
        }
    }
    cout<<f[n][0]+(n+1)*T;
    return 0;
}
posted @ 2026-10-02 10:10  farenara_sayowell  阅读(5)  评论(0)    收藏  举报