AT_abc376_f [ABC376F] Hands on Ring (Hard)

//记录一下如何想到具体DP转移方程的
//首先想令dp[i][j][k]表示第i次移动之前,左手在j位置,右手在k位置的情况。这样状态转移很简单,但是时间空间都会炸
//空间好办,直接滚动数组即可。至于时间,我们发现前一次移动之后有一只手的位置是固定的,这直接帮我们省掉了一维的时间和空间
//于是剩下的就变成模拟移动手的过程了,非常难写
#include<bits/stdc++.h>
    
using namespace std;
    
int t;
const int N = 2e5 + 10;
int n,q;
char s[N];
int u[N];
vector<vector<int> > dp(2,vector<int>(3010,1e9));
vector<int> tmp(3010,1e9);

pair<int,int> getnum(vector<int> a,int i,int pd) {
    int vv = u[i];
    char c = s[i];
    int pos = (c == 'L' ? 0 : 1);
    int op = pos ^ 1;
    if(vv == a[pos]) return {0,a[op]};
    if(pd == 0) {
        if(vv > a[pos]) {
            if(a[op] < a[pos]) a[op] += n;
            a[pos] += n;
            if(a[op] >= vv && a[pos] > a[op]) return {a[pos] - vv + a[op] - vv + 1,vv - 1 < 1 ? n : vv - 1};
            else return {a[pos] - vv,(a[op] > n ? a[op] - n : a[op])};
        }
        else {
            if(a[op] < a[pos] && a[op] >= vv) return {a[pos] - vv + a[op] - vv + 1,vv - 1 < 1 ? n : vv - 1};
            else return {a[pos] - vv,a[op]};
        }
    }
    else {
        if(vv > a[pos]) {
            if(a[op] > a[pos] && a[op] <= vv) return {vv - a[pos] + vv - a[op] + 1,vv + 1 > n ? 1 : vv + 1};
            else return {vv - a[pos],a[op]};
        }
        else {
            vv += n;
            if(a[op] < a[pos]) a[op] += n;
            if(a[op] > a[pos] && a[op] <= vv) return {vv - a[pos] + vv - a[op] + 1,vv % n + 1};
            else return {vv - a[pos],(a[op] > n ? a[op] - n : a[op])};
        }
    }
}

void solve() {
    cin >> n >> q;
    int now = 0,last = 1;
    dp[now][2] = 0;
    s[0] = 'L';
    u[0] = 1;
    for(int i = 1;i <= q;i++) {
        cin >> s[i] >> u[i];
        swap(now,last);
        dp[now] = tmp;
        for(int j = 1;j <= n;j++) {
            if(dp[last][j] >= 1e9) continue;
            pair<int,int> tmp;
            vector<int> tp(2);
            if(s[i - 1] == 'L')  tp[0] = u[i - 1],tp[1] = j;
            else tp[0] = j,tp[1] = u[i - 1];
            tmp = getnum(tp,i,0);
            dp[now][tmp.second] = min(dp[now][tmp.second],dp[last][j] + tmp.first);
            tmp = getnum(tp,i,1);
            dp[now][tmp.second] = min(dp[now][tmp.second],dp[last][j] + tmp.first);
        }
    }
    int ans = 1e9;
    for(int i = 1;i <= n;i++) ans = min(ans,dp[now][i]);
    cout << ans << '\n';
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    t = 1;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-04-30 14:20  孤枕  阅读(11)  评论(0)    收藏  举报