C. Messenger in MAC

C. Messenger in MAC

In the new messenger for the students of the Master's Assistance Center, Keftemerum, an update is planned, in which developers want to optimize the set of messages shown to the user. There are a total of n messages. Each message is characterized by two integers ai and bi. The time spent reading the set of messages with numbers p1,p2,,pk (1pin, all pi are distinct) is calculated by the formula:

i=1kapi+i=1k1|bpibpi+1|

Note that the time to read a set of messages consisting of one message with number p1 is equal to ap1. Also, the time to read an empty set of messages is considered to be 0.

The user can determine the time l that he is willing to spend in the messenger. The messenger must inform the user of the maximum possible size of the set of messages, the reading time of which does not exceed l. Note that the maximum size of the set of messages can be equal to 0.

The developers of the popular messenger failed to implement this function, so they asked you to solve this problem.

Input

Each test consists of multiple test cases. The first line contains a single integer t (1t5104) — the number of test cases. The description of the test cases follows.

The first line of each test case contains two integers n and l (1n2000, 1l109) — the number of messages and the time the user is willing to spend in the messenger.

The i-th of the next n lines contains two integers ai and bi (1ai,bi109) — characteristics of the i-th message.

It is guaranteed that the sum of n2 over all test cases does not exceed 4106.

Output

For each test case, output a single integer — the maximum possible size of a set of messages, the reading time of which does not exceed l.

Example

input

5
5 8
4 3
1 5
2 4
4 3
2 3
1 6
4 10
3 12
4 8
2 1
2 12
5 26
24 7
8 28
30 22
3 8
17 17
5 14
15 3
1000000000 998244353
179 239
228 1337
993 1007

output

3
1
2
1
0

Note

In the first test case, you can take a set of three messages with numbers p1=3, p2=2, and p3=5. The time spent reading this set is equal to a3+a2+a5+|b3b2|+|b2b5|=2+1+2+|45|+|53|=8.

In the second test case, you can take a set of one message with number p1=1. The time spent reading this set is equal to a1=4.

In the fifth test case, it can be shown that there is no such non-empty set of messages, the reading time of which does not exceed l.

 

解题思路

  赛时是用 dp 做的,看了下官方题解貌似还可以暴力贪心。

  首先对于任意一组选出的方案 p1,,pk,当 bp1bpk 时,i=1k1|bpibpi+1| 的部分一定有最小代价 bpkbp1

  这里给出简单证明,当 b 有序时,|bibi1|+|bi+1bi|=bi+1bi1。如果 b 不是有序,那么一定存在两个相邻元素前者比后者大,交换 bibi+1,此时 |bi+1bi1|+|bibi+1|=2bi+1bi1bi=bi+1bi1+bi+1bi>bi+1bi1。因此当相邻元素都是有序时,代价最小。

  假设现在数对 (ai,bi) 是按照 bi 从小到大排序的。定义 f(i,j) 表示从前 j 个数对中恰好选择了 i 个,且一定选择第 j 个数对的方案中代价最小值。根据上一个选择的数对进行状态划分,转移方程就是 f(i,j)=min1k<j{f(i1,k)bk}+aj+bj

  显然直接暴力转移的话时间复杂度是 O(n3)。可以发现对于固定 i,每次转移都是求前缀 k[1j1]f(i1,k)bk 的最小值,因此在枚举到 i 时依次遍历 j,并用 g(j) 来维护前缀 jf(i1,k)bk 的最小值。这样转移方程就变成了 f(i,j)=g(j1)+aj+bj

  最后暴力枚举 f(i,j) 的所有状态,如果 f(i,j)l 那么将答案与 i 取最大值。

  AC 代码如下,时间复杂度为 O(n2)

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

typedef long long LL;

const int N = 2010;
const LL INF = 0x3f3f3f3f3f3f3f3f;

int a[N], b[N], p[N];
LL f[N][N], g[N];

void solve() {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", a + i, b + i);
        p[i] = i;
    }
    sort(p + 1, p + n + 1, [&](int i, int j) {
        return b[i] < b[j];
    });
    for (int i = 1; i <= n; i++) {
        f[0][i] = f[i][0] = INF;
    }
    for (int i = 1; i <= n; i++) {
        g[0] = f[i - 1][0];
        for (int j = 1; j <= n; j++) {
            g[j] = min(g[j - 1], f[i - 1][j] - b[p[j]]);
        }
        for (int j = 1; j <= n; j++) {
            f[i][j] = g[j - 1] + a[p[j]];
            if (i > 1) f[i][j] += b[p[j]];
        }
    }
    int ret = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (f[i][j] <= m) ret = i;
        }
    }
    printf("%d\n", ret);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

  再给出贪心的做法。由于数对 (ai,bi) 已经按照 bi 从小到大排序,当选择的方案中第一个数对是 (al,bl),最后一个数对是 (ar,br),那么 i=1k1|bpibpi+1| 部分的代价是固定的 brbl。现在要在 [l,r] 中满足 ai+brbll 的条件下选择尽可能多的数对。显然贪心的做法是按照 ai 从小到大去选,直到不满足条件。

  所以具体做法是暴力枚举 lr,在固定 l 枚举 r 时开一个 std::priority_queue 存储 [l,r] 中的 ai,当 ai+brbll 不满足时把最大的元素从中删除。最后如果满足条件此时优先队列的大小就是最多能选择的数对,将其与答案取最大值。

  然后有疑问的地方是,如果此时优先队列中不同时存在 alar,那么这么做是否还是正确的?此时优先队列中的 ai 都来自 (l,r) 中的数对,意味着此时的代价 ak+brbl 一定不小于 ak+bibj,(l<ij<r),因此对答案没有影响。

  AC 代码如下,时间复杂度为 O(n2logn)

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

typedef long long LL;

const int N = 2010;

int a[N], b[N], p[N];

void solve() {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", a + i, b + i);
        p[i] = i;
    }
    sort(p + 1, p + n + 1, [&](int i, int j) {
        return b[i] < b[j];
    });
    int ret = 0;
    for (int i = 1; i <= n; i++) {
        LL s = 0;
        priority_queue<int> pq;
        for (int j = i; j <= n; j++) {
            s += a[p[j]];
            pq.push(a[p[j]]);
            while (!pq.empty() && s + b[p[j]] - b[p[i]] > m) {
                s -= pq.top();
                pq.pop();
            }
            if (s + b[p[j]] - b[p[i]] <= m) ret = max(ret, int(pq.size()));
        }
    }
    printf("%d\n", ret);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round #932 (Div. 2) Editorial:https://codeforces.com/blog/entry/126662

posted @   onlyblues  阅读(70)  评论(6编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-03-06 正则问题
2022-03-06 树的DFS
Web Analytics
点击右上角即可分享
微信分享提示