求助……
Catherine又跑上博客园来问题了……
7-9 策反加州
题目描述
来年一月份,特朗普将再次入主白宫,然而他却花了不少钱,这个时候,小 m 想知道,如果要让特朗普胜选,最少应该花多少钱。
因此,小 m 查询了美国选举制度,发现选举有以下几种形式:
一部分州在拿下一个州的一半及以上选民之后,即获得选票数要大于等于总票数的一半,就可以获得这个州的全部 张选举人票。
一部分州在则会按照比例分配,即会获得(选举人票数 自己获得的票数/该州所有选票数)下取整后的票数。
还有一部分州会采取如果选票超过或等于一半,即获得选票数要大于等于总票数的一半,则会获得固定的 张选举人票,其余还有 张选举人票按照比例分配,与第二种情况类似。
特朗普需要获得 的选票,或者获得或者超过 张选票,即可当选,而对于每个州而言,我们发现每多花 美元就可以使一个选民选择特朗普,请问,最小花费是多少,数据保证如果按照比例分配,则选民人数可以被选举人票数整除。
输入格式
第一行输入两个数个数 ,表示美国州的个数和获胜需要的选票数。
接下来 行,每行包含 个整数 ,分别表示按照一半以上分配的选举人票数,按照比例分配的选举人票数,选民总人数,在该州每收获一个选民需要的费用。显然,如果 ,则为第一种情况,如果 ,则为第二种情况,其余状况均为第三章情况。
输出格式
输出一行一个数,表示特朗普当选总统所需要的最小花费。
数据范围和约定
。
输入输出样例
输入样例 1
5 21
6 4 12 100
3 2 9 100
5 0 5 180
0 6 10 150
11 3 99 100
输出样例 1
2670
样例解释 1
总共有 40 张选票,我们先花 750 美元获得第 4 个州的全部选票 6 张,再花 600 美元获得第一个州 3 + 4 张选票,再花 720 美元获得第 3 个州的 4 张选票,最后耗费 600 美元获得第二个州的 2 + 2 张选票,共 21 张选票,花费 2570 元获得总统职位。
代码长度限制
16 KB
时间限制
1000 ms
内存限制
512 MB
栈限制
8192 KB
DeepSeek给的正解
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
#include <climits>
using namespace std;
const long long INF = 1e18;
class SparseTable {
private:
int n;
vector<vector<long long>> st;
vector<int> log_table;
public:
SparseTable(const vector<long long>& arr) {
n = arr.size();
if (n == 0) return;
int logn = 0;
while ((1 << logn) < n) logn++;
st.resize(logn + 1, vector<long long>(n));
for (int i = 0; i < n; i++) {
st[0][i] = arr[i];
}
for (int j = 1; j <= logn; j++) {
int step = 1 << (j - 1);
for (int i = 0; i + step < n; i++) {
st[j][i] = min(st[j - 1][i], st[j - 1][i + step]);
}
}
log_table.resize(n + 1);
log_table[1] = 0;
for (int i = 2; i <= n; i++) {
log_table[i] = log_table[i / 2] + 1;
}
}
long long query(int l, int r) {
if (l > r) return INF;
int len = r - l + 1;
int j = log_table[len];
return min(st[j][l], st[j][r - (1 << j) + 1]);
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t, w;
cin >> t >> w;
vector<long long> dp(w + 1, INF);
dp[0] = 0;
for (int idx = 0; idx < t; idx++) {
int N, M, p, x;
cin >> N >> M >> p >> x;
int m = (p + 1) / 2;
if (N == 0) {
long long cost_full = 1LL * m * x;
vector<long long> new_dp = dp;
for (int j = 0; j <= w; j++) {
if (dp[j] >= INF) continue;
int new_j = min(w, j + M);
new_dp[new_j] = min(new_dp[new_j], dp[j] + cost_full);
}
dp = new_dp;
} else if (M == 0) {
int K = p / N;
long long A = 1LL * K * x;
deque<int> dq;
vector<long long> new_dp(w + 1, INF);
for (int j = 0; j <= w; j++) {
while (!dq.empty() && dq.front() < j - N) {
dq.pop_front();
}
while (!dq.empty() && dp[dq.back()] - 1LL * dq.back() * A >= dp[j] - 1LL * j * A) {
dq.pop_back();
}
dq.push_back(j);
long long min_val = dp[dq.front()] - 1LL * dq.front() * A;
new_dp[j] = min_val + 1LL * j * A;
}
dp = new_dp;
} else {
int K = p / N;
long long A = 1LL * K * x;
deque<int> dq1;
vector<long long> new_dp1(w + 1, INF);
for (int j = 0; j <= w; j++) {
while (!dq1.empty() && dq1.front() < j - N) {
dq1.pop_front();
}
while (!dq1.empty() && dp[dq1.back()] - 1LL * dq1.back() * A >= dp[j] - 1LL * j * A) {
dq1.pop_back();
}
dq1.push_back(j);
long long min_val = dp[dq1.front()] - 1LL * dq1.front() * A;
new_dp1[j] = min_val + 1LL * j * A;
}
int g0 = (m + K - 1) / K;
int g_max_val = (m - 1) / K;
vector<long long> part1_arr(w + 1, INF);
vector<long long> part2_arr(w + 1, INF);
if (g0 <= N) {
vector<long long> F(w + 1);
for (int i = 0; i <= w; i++) {
F[i] = dp[i] - 1LL * i * A;
}
SparseTable st_F(F);
for (int j = 0; j <= w; j++) {
int low = j - M - N;
int high = j - M - g0;
if (low < 0) low = 0;
if (high > w) high = w;
if (low > high) continue;
long long min_F = st_F.query(low, high);
if (min_F >= INF) continue;
part1_arr[j] = min_F + 1LL * (j - M) * A;
}
}
if (g_max_val >= 0) {
SparseTable st_dp(dp);
for (int j = 0; j <= w; j++) {
int low = j - M - g_max_val;
int high = j - M;
if (low < 0) low = 0;
if (high > w) high = w;
if (low > high) continue;
long long min_dp_val = st_dp.query(low, high);
if (min_dp_val >= INF) continue;
part2_arr[j] = min_dp_val + 1LL * m * x;
}
}
for (int j = 0; j <= w; j++) {
long long best = min(new_dp1[j], min(part1_arr[j], part2_arr[j]));
dp[j] = best;
}
}
}
cout << dp[w] << endl;
return 0;
}
抄了一半想当鸽子
/*
mod 林钰翔 %%%
Catherine是HZOI鼎鼎大名的鸽子
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 3;
const long double INF = 1e18;
ll f[maxn], g[maxn];
int main()
{
int t, w; scanf("%d%d", &t, &w);
for(int i=1; i<=w; i++) f[i] = INF;
for(int i=1; i<=t; i++)
{
int N, M, p, x; scanf("%d%d%d%d", &N, &M, &p, &x);
int m = (p + 1) / 2;//以此为界,I know
if(N == 0)//要么买一半选票得到全部,要么放弃
{
ll c = m * x;
memcpy(g, f, sizeof(f));//滚动数组
//这个方程很好理解
for(int j=0; j<=w; j++)
{
if(f[j] >= INF) continue;
int p = min(w, j+M);
g[p] = min(g[p], f[j]+c);
}
memcpy(f, g, sizeof(g));
}
else if(M == 0)//比例分配
{
int K = p / N;//比例系数,购买个数*K等于票数
ll c = (ll)K * x;//买一张票的价格
for(int o=0; o<=w; o++) g[o] = INF;
deque<int> q;
//我天……单调队列优化dp,这绝不是我能写得出来的
for(int j=0; j<=w; j++)
{
//一个单调递增的队列,越往后越可能成为答案,值越小越可能成为答案
while(!q.empty() && q.front()<j-N) q.pop_front();
//上一个是从前找后,这个是从后找前
//但是这个排除我看不懂……
while(!q.empty() && f[q.back()]-(ll)q.back()*c>=f[j]-(ll)j*c) q.pop_back();
q.push_back(j);
ll val = f[q.front()]-(ll)q.front()*c;
g[j] = val + (ll)j * c;
}
memcpy(f, g, sizeof(g));
}
else
{
int K = p / N;
ll c = (ll)K * x;
for(int o=0; o<=w; o++) g[o] = INF;
deque<int> q;
for(int j=0; j<=w; j++)
{
while(!q.empty() && q.front()<j-N) q.pop_front();
while(!q.empty() && f[q.back()]-(ll)q.back()*c>=f[j]-(ll)j*c) q.pop_back();
q.push_back(j);
ll val = f[q.front()]-(ll)q.front()*c;
g[j] = val + (ll)j * c;
}
//以上是比例部分
//后面又是什么……无法理解!简直是无法理解!……鸽了吧孩子
}
}
return 0;
}
时光花火,水月星辰

浙公网安备 33010602011771号