Educational Codeforces Round 165 (Rated for Div. 2) (A~C)

前言

完全小瞧了edu的难度,感觉较上一场div2难多了

A. Two Friends (签到)

如果两个人互相是好友,那只用发两人,否则发三个人

void solve(){
    cin >> n;
    map<pair<int ,int> ,int> mp;
    for(int i = 1, x; i <= n; i++){
        cin >> x;
        mp[{x, i}]++;
        mp[{i, x}]++;
    }
    for(auto [a, b] : mp){
        if(b == 2){
            cout << 2 << endl;
            return;
        }
    }
    cout << 3 << endl;
}

B. Shifts and Sorting (签到)

题意是循环右移任意区间,使最后形成\(0-1\)的序列,费用是区间长度,求最小费用
观察样例可知一次移动多个\(0\)不如一个一个移动费用小,因为每多一个\(0,1\)就要多移动\(1\)步,比如\(100\),如果\(3\)格移,要移两次,花\(6\)费,而\(2\)格移动,同样是两次花\(4\)费,
所以模拟这个过程就行

void solve(){
    string s;
    int pre = 0;
    cin >> s;
    n = s.length();
    s = " " + s;
    int ans = 0;
    for(int i = 1; i <= n; i++){
        if(s[i] == '0'){
            if(i - pre > 1) // 如果和前个0相邻不用移动
                ans += (i - pre);
            pre++; 
        }
    }
    cout << ans << endl;
}

C. Minimizing the Sum (dp)

题意是给你一个数组,你可以执行以下操作:从数组中选择一个元素,并用其邻近元素的值替换它,最多执行\(k\)次。计算数组的最小总和。
这边的做法略显麻烦,感觉不太像正解:
观察得到 \(k < 10\),考虑 \(dp[n][k]\)符合复杂度,那么\(dp[i][j]\)状态显然是到第\(i\)个元素为止,进行k次操作最多能使总和减少多少。(直接记录答案应该也行)
当遍历到\(i,j\)的时候,记之前已经进行了多少次操作,设为\(last\),得到这一位的影响是是将前方最多\(pre\)\((pre <= j - last)\)个元素变成\(a_i\),后方最多 \((j - last - pre)\)个元素变成\(a_i\)
那么转移方程就得到了\(dp[i + j - last - pre][j] = max(dp[i + j - last - pre][j], dp[i - pre - 1][last] + l[i][pre] + r[i][j - last - pre])\)
预处理\(l[i][j]\)表示将前面\(j\)个元素全都变成\(a_i\)导致的总和减少量。\(r[i][j]\)同理。
细节看代码

const int N = 3e5 + 9, inf = 0x3f3f3f3f;
int n, m, k;
int dp[N][11];
int a[N];
int l[N][11], r[N][11];
void solve(){
    cin >> n >> k;
    int sum = 0;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        sum += a[i];
    }
    for(int i = 1; i <= n; i++){ //初始化
        for(int j = 0; j <= 10; j++){
            dp[i][j] = 0;
        }
    }
    for(int i = 1; i <= n; i++){ //预处理
        l[i][0] = 0;
        for(int j = 1; j <= 10; j++){
            if(i - j >= 1)
                l[i][j] = l[i][j - 1] + (a[i - j] - a[i]);  
            if(i + j <= n)
                r[i][j] = r[i][j - 1] + (a[i + j] - a[i]);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 0; j <= 10; j++){  //当然可以从i-1,j转移过来
            dp[i][j] = max(dp[i - 1][j], dp[i][j]);
        }
        for(int j = 0; j <= 10; j++){
            for(int last = 0; last <= j; last ++){
                for(int pre = 0; pre <= j - last; pre++){
                    if(i - pre - 1 >= 0 && j - pre >= 0 && i + j - last - pre <= n && i - pre >= 1)  //边界处理
                        dp[i + j - last - pre][j] = max(dp[i + j - last - pre][j], dp[i - pre - 1][last] + l[i][pre] + r[i][j - last - pre]);
                }
            }
        }
    }   
    int minn = 0; 
    for(int i = 0; i <= k; i++){
        minn = max(minn, dp[n][i]);
    }
    cout << sum - minn << endl;
}
posted @ 2024-04-30 00:46  SHOJIG  阅读(609)  评论(0)    收藏  举报