首页 > 其他分享 >P6646 [CCO2020] Shopping Plans 题解

P6646 [CCO2020] Shopping Plans 题解

时间:2024-02-23 10:26:01浏览次数:27  
标签:pr pre P6646 Shopping val int 题解 cr now

好好玩的题。

思路

对于前 \(K\) 小方案问题。

我们可以考虑当前方案对下一个方案的转移。

重点在于转移的最优化与不重不漏。

只有一种种类

假设没有 \(l,r\) 的限制怎么做。

我们不妨把所有价格排序。

发现一种状态转移到另一种状态,无异与将其中已选择的一个物品不选,选择他后面的一个物品。

这样可以得到一个更劣的状态。

考虑使用 \((now, nxt, val)\) 来表示当前状态。

\(now\) 表示我们当前准备不选的物品。

\(nxt\) 表示 \(now\) 后面第一个选择的物品。

那么有转移:

\[(now,nxt,val)\rightarrow(now+1,nxt,val-c_{now}+c_{now+1}) \]

当然,这样的转移没有包括所有的物品。

那么我们不妨在加入一维。

考虑使用 \((pre, now, nxt, val)\) 来表示当前状态。

\(pre\) 表示 \(now\) 前面有几个元素,由于 \(pre\) 个元素都没有位移过,所以它必然是一段 \(1\sim pre\) 的前缀。

那么有转移:

\[(pre,now,nxt,val)\rightarrow(pre,now+1,nxt,val-c_{now}+c_{now+1}) \]

\[(pre,now,nxt,val)\rightarrow(pre-1,pre,now,val) \]

发现第二种转移与当前的方案是同一种,所以我们可以钦定每一次转移必须位移一次。

那么有:

\[(pre,now,nxt,val)\rightarrow(pre-1,pre+1,now,val-c_{pre}+c_{pre+1}) \]

初始状态为:

\[(i,i,n+1,sum_i) \]

至于 \(l,r\) 的限制也变得比较简单。

\[i\in[l,r],(i,i,n+1,sum_i) \]

有多种种类

可以发现,每一种种类之前是比较独立的。

所以我们同样可以用之前的方法求出单种种类的第 \(k\) 小。

设 \(kth_j(i)\) 为第 \(j\) 种颜色中,第 \(i\) 小的方案。

使用同样的状态维护外层的贪心。

\((now,k,val)\) 表示当前在第 \(now\) 个颜色,使用的是第 \(k\) 小方案。

那么有转移:

\[(now,k,val)\rightarrow(now,k+1,val-kth_{now}(k)+kth_{now}(k+1)) \]

\[(now,k,val)\rightarrow(now+1,2,val-kth_{now+1}(1)+kth_{now+1}(2)) \]

这样的转移还存在一点瑕疵。

我们有可能会跳过一些颜色。

那么对于 \(k=2,now\not = 1\),我们有转移:

\[(now,2,val)\rightarrow(now+1,2,val-(kth_{now+1}(1)-kth_{now+1}(2))+(kth_{now}(1)-kth_{now}(2))) \]

这样,我们把所有颜色按 \(kth(1)-kth(2)\) 从大到小排序,就可以正常转移了。

初始状态 \((1,1,\sum kth(1))\)。

时间复杂度:\(O(k\log k)\)。

Code

#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
#define int long long
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for(int i = (x); i <= (y); i++)
#define pre(i, x, y) for(int i = (x); i >= (y); i--)
inline void JYFILE19();

typedef long long i64;
typedef pair<int, int> PII;

bool ST;
const int N = 1e6 + 10;
const int mod = 998244353;

int n, m, k, ct, ans, a[N], c[N], id[N];
vector<int> d[N], g[N];
struct Node {
  int pr, cr, nt, vl;
  inline bool operator<(const Node &tmp) const {
    return vl > tmp.vl;
  }
};

priority_queue<Node> q[N], f;

inline int get(int p) {
  if(q[p].empty()) return -1;
  auto x = q[p].top(); q[p].pop();
  if(x.cr && x.cr + 1 < x.nt)
    q[p].push({x.pr, x.cr + 1, x.nt, x.vl - d[p][x.cr] + d[p][x.cr + 1]});
  if(x.pr && x.pr + 1 < x.cr)
    q[p].push({x.pr - 1, x.pr + 1, x.cr, x.vl - d[p][x.pr] + d[p][x.pr + 1]});
  return x.vl;
}
inline int ask(int p, int k) {
  while(k > g[p].size()) {
    int v = get(p); g[p].eb(v);
  }
  return g[p][k - 1];
}
inline int ask() {
  if(f.empty()) return -1;
  auto x = f.top(); f.pop();
  if(x.cr + 1 == 2 && ask(id[x.pr], 2)) {
    f.push({x.pr, x.cr + 1, ask(id[x.pr], 2), x.vl - x.nt + ask(id[x.pr], 2)});
  }
  if(x.cr + 1 != 2) {
    int v = ask(id[x.pr], x.cr + 1);
    if(v != -1) {
      f.push({x.pr, x.cr + 1, v, x.vl - x.nt + v});
    }
  }
  if(x.pr + 1 <= ct) {
    f.push({x.pr + 1, 2, ask(id[x.pr + 1], 2), x.vl - ask(id[x.pr + 1], 1) + ask(id[x.pr + 1], 2)});
  }
  if(x.pr != 1 && x.cr == 2 && x.pr + 1 <= ct) {
    f.push({x.pr + 1, 2, ask(id[x.pr + 1], 2), x.vl - ask(id[x.pr + 1], 1) + ask(id[x.pr + 1], 2) + ask(id[x.pr], 1) - ask(id[x.pr], 2)});
  }
  return x.vl;
}

signed main() {
  JYFILE19();
  cin >> n >> m >> k;
  fro(i, 1, n) cin >> a[i] >> c[i];
  fro(i, 1, n) d[a[i]].eb(c[i]);
  fro(i, 1, m) {
    d[i].eb(0);
    sort(d[i].begin(), d[i].end());
    int x, y, sm = 0, len = d[i].size();
    cin >> x >> y;
    x = min(x, len);
    y = min(y, len - 1);
    fro(j, 1, x - 1)
      sm += d[i][j];
    fro(j, x, y) {
      sm += d[i][j];
      q[i].push({j - 1, j, len, sm});
    }
  }
  int res = 0;
  fro(i, 1, m) {
    if(ask(i, 1) == -1) {
      fro(i, 1, k) {
        cout << -1 << "\n";
      }
      return 0;
    }
    if(ask(i, 2) != -1) {
      id[++ct] = i, res += ask(i, 1);
    }
    else {
      ans += ask(i, 1);
    }
  }
  if(ct == 0) {
    cout << ans << "\n";
    fro(i, 2, k) {
      cout << -1 << "\n";
    }
    return 0;
  }
  sort(id + 1, id + ct + 1, [&](int x, int y) {
    return ask(x, 1) - ask(x, 2) > ask(y, 1) - ask(y, 2);
  });
  f.push({1, 1, ask(id[1], 1), res});
  fro(i, 1, k) {
    int x = ask();
    cout << (x == -1 ? x : x + ans) << "\n";
  }
  return 0;
}

bool ED;
inline void JYFILE19() {
  // freopen("", "r", stdin);
  // freopen("", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  double MIB = fabs((&ED-&ST)/1048576.), LIM = 500;
  cerr << "MEMORY: " << MIB << endl, assert(MIB<=LIM);
}

标签:pr,pre,P6646,Shopping,val,int,题解,cr,now
From: https://www.cnblogs.com/JiaY19/p/18028889

相关文章

  • process.env.API_KEY undefined问题解决
    问题现象已经在root路径下面创建.env文件,但是使用process.env.API_KEY获取不到值。分析获取不到env文件中的值,检查env文件已配置API_KEY,检查是否安装了dotenv,检查是否导入配置了dotenv解决方法在index.ts中导入import'dotenv/config';应该在使用env的模块前面就导入dote......
  • 2024.2.22模拟赛T3 题解
    对于区间连边,可以线段树优化建图对于单点连边,可以使用李超线段树维护迪杰斯特拉code#include<bits/stdc++.h>usingnamespacestd;#defineN400005#defineintlonglong#definepiipair<int,int>#definefirfirst#definesecsecondintn,m,tot;intval[N];const......
  • 数星星题解补充
    题解中那个看似暴力的染色,实际上正确性显然,直接看75%的时间复杂度证明然后还是直接看75分的部分它的里面说是用set维护块的前驱后继,然后全网没有一篇这样的题解,似乎全世界就我一个用这个方法于是想了一中午终于想到如何维护:就是用set记录每一个块的最后一个的位置,由于是区间覆......
  • P3870 分块题解
    这篇题解有点问题(分块标记处),但现在不想修,等有空修吧link分块是一种很神奇的暴力,学了它就会觉得什么都可以用分块做。分块的主要思想就是整块快速查询,散块暴力查询。比如说,分块可以在\(O(q\sqrt{n}+n)\)的时间复杂度内解决线段树模板题。回到本题,显然我们可以用每个块维护......
  • CF1372F Omkar and Modes 题解
    来个乱搞。思路考虑分治。对于最裸的暴力。我们可以调用solve(l,r)进行查询。假如这个区间的众数的出现次数是区间长度,那么可以直接退出,否则我们可以继续分治。我们把这个暴力进行加工一下。我们知道\(l\simr\)的区间众数后。查询\(l\simmid\)的区间众数,若完全......
  • CF1845F Swimmers in the Pool 题解
    思路考虑两个人什么时候会相遇。根据小学的相遇追及问题,两人会相遇的条件为:\[2\timesk\timesl=t\times(v1+v2)\]\[2\timesk\timesl=t\times(v1-v2)\]那么对于一个速度\(v\)。它可一相遇的次数即为:\[\frac{t\timesv}{2\timesl}\]当然,这样有可能会算重,也就是在相同......
  • 山海经(线段树)题解
    原题链接:COGS775题目描述:“南山之首曰鹊山。其首曰招摇之山,临于西海之上,多桂,多金玉。有草焉,其状如韭而青华,其名曰祝余,食之不饥……又东三百里,曰堂庭之山,多棪木,多白猿,多水玉,多黄金。又东三百八十里,曰猨翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上。……”(其实就......
  • 玉蟾宫 题解
    题目描述有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。这片土地被分成N*M个格子,每个格子里写着’R’或者’F’,R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。现在freda要在这里卖萌。。。它要找一块......
  • P6466 分散层叠算法(Fractional Cascading) 题解
    题目链接:分散层叠算法比较妙的东西,在很多涉及到若干个有序块的\(kth\)查询的ynoi题中都有妙用。这里简单提提。两种暴力解法在其他文章已有涉及,在此不再赘述。讲讲具有该怎么写这个算法,首先我们需要预处理出新的\(k\)个序列,不妨记每个为\(M_i\)。\(M_{n}=L_n\),其中\(L\)......
  • [ABC259Ex] Yet Another Path Counting 题解
    Description有\(N\)行\(N\)列的网格图,只能向下或向右走,合法路径的开端和结尾的格子上数字一样找到合法路径条数,对\(998244353\)取模\(1\leqN\leq400,1\leqa_{i,j}\leqN^2\)。Solution有一个\(O(n^4)\)的做法是每次枚举起点和终点然后用组合数计算答案,但是由于同......