CF1437C (dp,排序去除后效性)

CF1437C (dp,排序去除后效性)

题意

\(n\) 个菜,每个菜有一个出锅时间 \(t_i\) ,每一个整数时刻 \(T\) 可以取出一道菜。定义 \(|T-t_i|\) 为每道菜的不美味值,求最小的不美味值的和。

\(n \le 200\)

思路

考虑dp。定义 \(dp[i][j]\) 表示取出了 \(i\) 道菜且最后一道菜取出时间为 \(j\) 的答案。这里就会出现问题,我们并不知道 \(j\) 时刻之前是否有菜已经取出。未来和过去有关,后效性存在。

此时我们将出锅时间排序,就可以修改定义 \(dp[i][j]\) 表示取出了 \(i\) 道菜且这 \(i\) 道菜都在 \([1,j]\) 时间取出,且最后一道菜取出时间为 \(j\) 的答案。此时后效性消失。


我们为什么可以这样做呢。当排序后,从 \(t_i\) 最小开始处理,如果 \(t_i < t_j\)\(j\) 安排的时间一定比 \(i\) 大。这是因为 如果 \(T_i>T_j\) 。则 \(|t_i-T_i|+|t_j-T_j| \ge |t_i-T_j| + |t_j-T_i|\) 显然成立(画个数轴看看就知道了)。因此如果知道最后一个菜安排的时间 \(j\) ,安排下一道菜就不再考虑 \([1,j]\) 的时间了。从而满足无后效性。


考虑转移,\(dp[i][j] =min\{ dp[i - 1][k] + |j - t_i|\},k \in [i-1,j-1]\) 。这里面 \(k\) 的枚举可以用前缀最小值优化,做到 \(O(n^2)\) 。不过本题数据量过水,\(O(n^3)\) 也是可以接受的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<random>
#include<iomanip>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int n; cin >> n;
    vector<int> a(n + 1);
    for(int i = 1;i <= n;i += 1) cin >> a[i];
    sort(a.begin() + 1,a.end());
    vector<vector<int>> f(n + 1,vector<int>(401,inf));
    for(int j = 0;j <= 400;j += 1) f[0][j] = 0;
    for(int i = 1;i <= n;i += 1) {
        vector<int> mn(401,inf);
        for(int j = i - 1;j <= 400;j += 1) mn[j] = min(j - 1 >= 0 ? mn[j - 1] : inf,f[i - 1][j]);
        for(int j = i;j <= 400;j += 1) {
        //     f[i][j] = min(f[i][j], f[i - 1][k] + abs(a[i] - j));
            f[i][j] = min(f[i][j], mn[j - 1] + abs(a[i] - j));
        }
    }
    int ans = *min_element(f[n].begin(),f[n].end());
    cout << ans << endl;

}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}
posted @ 2022-07-13 18:48  Mxrurush  阅读(42)  评论(0编辑  收藏  举报