【LGR-250】洛谷 NOIP 2025 模拟赛

【LGR-250】洛谷 NOIP 2025 模拟赛

比赛链接:【LGR-250】洛谷 NOIP 2025 模拟赛

A.mexdnc

原题链接:缺零分治 mexdnc

分析

考场上推出神秘性质——只能从$0$到$mex$取数,而出入的$m$也必须在这个最大和的范围,从大到小取从贪心角度解释是优的,找到第一个大于等于的前缀和即可?好了,思路如此,看看代码写成啥了——$RE\times2,WA\times3,AC\times2,MLE\times 13$,那还说啥?HE一篇题解。

正解

#include<bits/stdc++.h>
using namespace std;
int T, n, q;
struct node{
    long long a, b;
}inp[100010];
long long sum[100010], cnt_sum[100010];
long long m;
int main(){
    // freopen("mexdnc.in","r",stdin);
    // freopen("mexdnc.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> T;
    while (T--){
        cin >> n >> q;
        for (int i = 1; i <= n; i++) 
            cin >> inp[i].a >> inp[i].b;
        inp[0].b = 0x3f3f3f3f3f3f3f3f;
        long long mex = 0;
        for (int i = 1; i <= n; i++){
            if (mex == inp[i].a){
                mex++;
                inp[i].b = min(inp[i - 1].b, inp[i].b);
            } 
            else 
                break;
        }
        n = mex;
        inp[n + 1].b = 0;
        for (int i = 1; i <= n; i++){
            inp[i].a = i;
            inp[i].b -= inp[i + 1].b;
        } 
        reverse(inp + 1, inp + 1 + n);
        for (int i = 1; i <= n; i++){
            sum[i] = sum[i - 1] + inp[i].a * inp[i].b;
        } 
        for (int i = 1; i <= n; i++){
            cnt_sum[i] = cnt_sum[i - 1] + inp[i].b;
        } 
        while (q--){
            cin >> m;
            if (n == 0){
                if (m == 0) 
                    cout << 1 << '\n';
                else 
                    cout << -1 << '\n';
                continue;
            }
            if (m == 0 || m > sum[n]){
                cout << -1 << '\n';
                continue;
            }
            if (m == sum[n]){
                cout << cnt_sum[n] << '\n';
                continue;
            }
            if (m < inp[1].a){
                cout << 2 << '\n';
                continue;
            }
            int l = 1, r = n + 1;
            while (l < r){
                int mid = (l + r) >> 1;
                if (sum[mid] <= m) 
                    l = mid + 1;
                else 
                    r = mid;
            }
            long long ans = cnt_sum[l - 1] + (m - sum[l - 1] + inp[l].a - 1) / inp[l].a;
            cout << ans << '\n';
        }
        memset(inp, 0, sizeof(inp));
        memset(sum, 0, sizeof(sum));
        memset(cnt_sum, 0, sizeof(cnt_sum));
    }
}

B.guess

原题链接:猜数游戏 guess

分析

好的,其实是数轴,比较类似于交互?

08点55分

是不是先用性价比最高的从$[1,n]$跑一遍,进一步缩小范围然后再跑再跑?感觉很假,我去问问。

08点57分

啥?$DP?$那假了,盯一下状态……

09点03分

呃,我理解对题目了吗?好吧,就是说来到区间中点,我们一定知道目标在区间哪一部分,难道走$logn$步一定优吗?也不一定,因为花费没有任何规律,那么就把在区间左部还是右部记入状态?但是,如果设成类似区间$DP$的形式显然时间跑不下。所以要优化掉一维,

设$f_{i,0/1}$表示长度为$i$的区间从左/右转移的最大花费,发现第二维没用,直接省略掉。那么,直接设$f_i$表示长度为$i$的区间最大花费,转移即为

$f_i=\min\limits_{j\in [1,i]}(cost_j+\min(f_{j},f_{i-j}))$

真的没抄题解,纯抄$mhh$的!

考虑如何获得到达某个点的$cost_j$……背包被Hack了,贪心是较为正确的。

09点20分

呃,写完了转移方程。贪心过程居然形如最短路状物!!!呃,这个不建图的Trick我似乎并不会,开始HE题解。

10点21分

终于写出来正解了/(ㄒoㄒ)/~~

正解

#include <bits/stdc++.h>
#define int long long
using namespace std; 
const int N = 10005, M = 1005;
const long long INF = 0x3f3f3f3f3f3f3f3f;
int c, T;
int n, m, maxv;
struct node{
    int a, b;
}inp[M];
long long cost[N << 1], f[N];
priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> q;
void dijkstra(){
    for (int i = -maxv; i <= maxv; i++)
        cost[i + N] = INF;
    cost[N] = 0;
    q.push({0, 0});
    while (!q.empty()){
        auto tmp = q.top();
        q.pop();
        int w = tmp.first, u = tmp.second;
        if (w != cost[u + N])
            continue;
        for (int i = 1; i <= m; i++){
            if (u + inp[i].a <= maxv){
                int v = u + inp[i].a;
                if (cost[u + N] + inp[i].b < cost[v + N]){
                    cost[v + N] = cost[u + N] + inp[i].b;
                    q.push({cost[v + N], v});
                }
            }
            if (u - inp[i].a >= -maxv){
                int v = u - inp[i].a;
                if (cost[u + N] + inp[i].b < cost[v + N]){
                    cost[v + N] = cost[u + N] + inp[i].b;
                    q.push({cost[v + N], v});
                }
            }
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> c >> T;
    while (T--){
        maxv = 0;
        cin >> n >> m;
        for (int i = 1; i <= m; i++){
            cin >> inp[i].a;
            maxv = max(maxv, inp[i].a);
        }
        for (int i = 1; i <= m; i++)
            cin >> inp[i].b;
        dijkstra();
        for (int i = 0; i <= n; i++)
            f[i] = INF;
        f[1] = 0;
        for (int i = 2; i <= n; i++){
            for (int j = 1; j <= maxv && j <= i; j++){
                f[i] = min(f[i], max(f[j], f[i - j]) + cost[j + N]);
            }
        }
        if (f[n] != INF)
            cout << f[n] << '\n';
        else
            cout << -1 << '\n';
    }
    return 0;
}

由于存在负半轴,注意开两倍。

C.tree

原题链接:树上求值 tree

分析

这个就开始阴了,毕竟是紫题,我认为到11:30前写出来就很好了。

我决定不补了,或是因为浮躁,但是我并未真正看懂题目,再见。

D.miss

原题链接:夜里亦始终想念着你 miss

分析

我甚至认为这题更可补。

呃,场上 出现了幻觉,认为甚至$T4$更简单,显然不。感觉是比较复杂的容斥+组合数?

我需要题解。

好吧,似乎也不可补……撤了。

posted on 2025-11-18 20:50  hetao1733837  阅读(22)  评论(0)    收藏  举报

导航