abc317D 選舉總統

chenfy27發表於2024-03-09

題面:有n個區,第i個區有x[i]+y[i]個選民,其中x[i]支援A,y[i]支援B,支援人數多的一方獲得該區的全部票數z[i],全部區的票數之和多者獲勝,問至少還要多少選民從支援B改為支援A,才能讓A勝出?
範圍:1<=n<=100; 0<=x[i],y[i]<=1E9; x[i]+y[i]為奇數, z[i]>=1,z[i]之和為奇數且不超過1E5。

思路:將各個區看成物品,對於第i個區,如果x[i]>y[i],那麼花費為0;否則要讓x[i]增加到過半數,花費為(x[i]+y[i]+1)/2 - x[i]。綜合得,第i個區的花費為max(0, (y[i]-x[i]+1)/2),價值為z[i]。
如果正常跑01揹包,dp[i]表示花費為i時所能取到的最大價值,跑完後遍歷dp找到值大於zsum/2的下標。但本題花費很大,而價值較小,因此定義dp[j]為取到價值j時所需的最小花費,跑完後遍歷dp找到滿足條件j值的最小dp[j]即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for(int i=a; i<=b; i++)
#define per(i,a,b) for(int i=b; i>=a; i--)

const int N = 105;
const int M = 1E5+5;
const int inf = 1E18;
int n, m, c[N], w[N], dp[M];
void solve() {
    cin >> n;
    rep(i,1,n) {
        int x, y, z;
        cin >> x >> y >> z;
        c[i] = max(0LL, (y-x+1)/2);
        w[i] = z;
        m += z;
    }
    rep(i,1,m) dp[i] = inf;
    rep(i,1,n) per(j,w[i],m) {
        dp[j] = min(dp[j], dp[j-w[i]]+c[i]);
    }
    int ans = inf;
    rep(i,0,m) if(i+i>m) {
        ans = min(ans, dp[i]);
    }
    cout << ans << "\n";
}

signed main() {
    cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

相關文章