『模拟赛』NOIP2024加赛4

Rank

给我唐完了,

image

又名,【MX-S5】梦熊 NOIP 2024 模拟赛 1


A. 王国边缘

好像简单倍增就做完了。

由于昨天 T5 在我脑海中留下了挥之不去的印象,今天一上来看到这题就发现是一个内向基环树森林。然后被硬控硬控硬控,最后一个小点加一点优化就能过没调出来,挂 30pts,菜菜菜菜菜。

注意到倍增理论复杂度是 \(\mathcal{O(n\log n)}\) 的,而我们基环树玩家的理论复杂度可以做到完全线性,所以一下午直接调出了 8.2k 基环树做法。

中途插曲还不少,包括但不限于判完完整环之后暴力查询过了,轻松卡成 \(\mathcal{O(n^2)}\);然后在环上加了前缀和优化,不过链上还是 \(\mathcal{O(n)}\) 跑,又过了;尝试交题解,被告知要贴代码,遂加入离线 dfs 优化,至此达成 \(\mathcal{O(n)}\)

具体做法见此

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
ll n, m, q;
string s;
int las[N], fx[N], dfn[N], dt;
int hh[N], to[N], ne[N], cnt;
bool huan[N], vis[N], yz[N];
int bushu[N], daxiao[N], jieru[N];
ll len[N], w[N], dep[N], dis[N];
int newid[N], tot, st[N];
ll sumid[N];
ll ans[N];
namespace Wtask
{
    short main()
    {
        m %= mod;
        fo(i, 1, q)
        {
            ll qd = qr, k = qr;
            qd %= mod;
            k %= mod;
            printf("%lld\n", (qd + k * m % mod) % mod);
        }
        return Ratio;
    }
}
int h1[N], t1[N], n1[N], tnc;
ll w1[N];
vector<pii> que[N];
namespace Wlixian
{
    int deep[N];
    ll shendu[N];
    inline void Wdfs(int u, int sd)
    {
        for(pii qq : que[u])
        {
            int x = qq.fi, y = qq.se;
            ans[y] = (ans[y] + (shendu[u] - shendu[deep[sd - x]] + mod) % mod) % mod;
        }
        for(int i = h1[u]; i != -1; i = n1[i])
        {
            int v = t1[i];
            if(huan[v]) continue;
            deep[sd + 1] = v;
            shendu[v] = (shendu[u] + w1[i]) % mod;
            Wdfs(v, sd + 1);
        }
    }
    inline void Wwork()
    {
        fo(i, 1, n) if(huan[i]) deep[1] = i, Wdfs(i, 1);
    }
}
namespace Wisadel
{
    int siz[N];
    inline int Wfind(int x)
    {
        if(x == fx[x]) return x;
        return fx[x] = Wfind(fx[x]);
    }
    inline void Wmerge(int u, int v)
    {
        int _ = Wfind(u), __ = Wfind(v);
        if(siz[_] < siz[__]) fx[_] = __, siz[__] += siz[_];
        else fx[__] = _, siz[_] += siz[__];
    }
    inline void Wadd(int u, int v, ll val)
    {
        to[++cnt] = v;
        w[cnt] = val;
        ne[cnt] = hh[u];
        hh[u] = cnt;
    }
    inline void Wda(int u, int v, ll val)
    {
        t1[++tnc] = v;
        w1[tnc] = val;
        n1[tnc] = h1[u];
        h1[u] = tnc;
    }
    int tag = 1e9;
    inline void Wsearch(int u, int id, int tar)
    {
        newid[u] = id;
        for(int i = hh[u]; i != -1; i = ne[i])
        {
            int v = to[i];
            if(v == tar) return ;
            sumid[id + 1] = sumid[id] + w[i];
            Wsearch(v, ++tot, tar);
        }
    }
    inline void Wdfs(int u)
    {
        yz[u] = 1;
        vis[u] = 1;
        dfn[u] = ++dt;
        for(int i = hh[u]; i != -1; i = ne[i])
        {
            int v = to[i];
            if(vis[v])
            {
                tag = dfn[v];
                huan[u] = 1;
                sumid[++tot] = 0;
                st[Wfind(u)] = tot;
                Wsearch(v, ++tot, v);
                len[Wfind(u)] = (dep[u] - dep[v] + w[i] + mod) % mod;
            }
            else if(yz[v]) continue;
            else dep[v] = (dep[u] + w[i]) % mod, Wdfs(v);
        }
        vis[u] = 0;
        if(dfn[u] >= tag) jieru[u] = u, huan[u] = 1, daxiao[Wfind(u)]++;
        if(dfn[u] == tag) tag = 1e9;
    }
    inline void Wdfss(int u)
    {
        yz[u] = 1;
        for(int i = hh[u]; i != -1; i = ne[i])
        {
            int v = to[i];
            if(huan[v]) dis[u] = w[i], bushu[u] = 1, jieru[u] = v;
            else Wdfss(v), dis[u] = dis[v] + w[i], bushu[u] = bushu[v] + 1, jieru[u] = jieru[v];
        }
    }
    short main()
    {
        freopen("kingdom.in", "r", stdin), freopen("kingdom.out", "w", stdout);
        n = qr, m = qr, q = qr;
        fo(i, 1, n) fx[i] = i, siz[i] = 1;
        memset(h1, -1, sizeof h1);
        memset(hh, -1, sizeof hh);
        cin >> s;
        s = " " + s;
        int zaisuan = -1;
        fo(i, 1, n) if(s[i] == '1'){zaisuan = i - 1; break;}
        if(zaisuan == -1)
        {
            fo(i, 1, q)
            {
                ll qd = qr, k = qr;
                qd %= mod;
                k %= mod;
                printf("%lld\n", (qd + k) % mod);
            }
            return Ratio;
        }
        int ok = 1;
        fo(i, 1, n) if(s[i] != '1'){ok = 0; break;}
        if(ok) return Wtask::main();
        fo(i, zaisuan + 1, n) las[i] = s[i] == '1' ? i : las[i - 1];
        fo(i, 1, zaisuan) las[i] = las[n] - n;
        fo(i, 1, n)
        {
            if(i + m <= n)
            {
                ll dis;
                if(las[i + m] <= i)
                {
                    dis = 1;
                    Wmerge(i + 1, i);
                    Wadd(i, i + 1, dis);
                    Wda(i + 1, i, dis);
                }
                else
                {
                    dis = las[i + m] - i;
                    Wmerge(las[i + m], i);
                    Wadd(i, las[i + m], dis);
                    Wda(las[i + m], i, dis);
                }
            }
            else if(m < n)
            {
                int to = (m - (n - i)) % n;
                int zto = to;
                if(las[to] <= 0)
                {
                    zto = las[to] + n;
                    if(zto <= i)
                    {
                        ll dis = 1;
                        zto = i + 1;
                        if(zto > n) zto = 1;
                        Wmerge(zto, i);
                        Wadd(i, zto, dis);
                        Wda(zto, i, dis);
                    }
                    else
                    {
                        ll dis = zto - i;
                        Wmerge(zto, i);
                        Wadd(i, zto, dis);
                        Wda(zto, i, dis);
                    }
                }
                else
                {
                    ll dis = las[to] - i + n;
                    Wmerge(las[to], i);
                    Wadd(i, las[to], dis);
                    Wda(las[to], i, dis);
                }
            }
            else
            {
                ll to = (m - (n - i)) % n;
                ll tim = (m - (n - i)) / n;
                if(!to) to += n, tim--;
                int zto = las[to];
                if(zto <= 0) zto += n, tim--;
                ll dis = (n - i + zto + tim * n % mod) % mod;
                Wmerge(zto, i);
                Wadd(i, zto, dis);
                Wda(zto, i, dis);
            }
        }
        fo(i, 1, n) if(!yz[i]) Wdfs(i);
        fill(yz + 1, yz + 1 + n, 0);
        fo(i, 1, n) if(!yz[i] && !huan[i]) Wdfss(i);
        fo(i, 1, q)
        {
            ll qidian = qr, cishu = qr, res = 0;
            if(cishu == 0)
            {
                ans[i] = qidian % mod;
                continue;
            }
            int dxqidian = qidian % n;
            if(!dxqidian) dxqidian = n;
            int belong = Wfind(dxqidian);
            res = qidian % mod;
            if(cishu < bushu[dxqidian]) que[dxqidian].P_B(M_P(cishu, i));
            else
            {
                cishu -= bushu[dxqidian];
                ll timesl = cishu / daxiao[belong];
                cishu -= timesl * daxiao[belong];
                timesl %= mod;
                res = (res + timesl * len[belong] % mod) % mod;
                res = (res + dis[dxqidian]) % mod;
                if(cishu)
                {
                    if(newid[jieru[dxqidian]] - st[belong] + cishu <= daxiao[belong]) res = ((res + sumid[newid[jieru[dxqidian]] + cishu]) % mod - sumid[newid[jieru[dxqidian]]] + mod) % mod;
                    else
                    {
                        int zcc = newid[jieru[dxqidian]] + cishu - daxiao[belong];
                        res = (res + ((sumid[zcc] - sumid[newid[jieru[dxqidian]]] + mod) % mod + len[belong]) % mod) % mod;
                    }
                }
            }
            ans[i] = res;
        }
        Wlixian::Wwork();
        fo(i, 1, q) printf("%lld\n", ans[i]);
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// 佳墙坂诶迦币等渔塞

B. 买东西题

反悔贪心板子。

其实做完两个特殊性质就把正解启发得差不多了,结合一下就过了。

考虑物品按 \(a_i\) 升序,券按 \(w_i\) 升序,双指针扫,这样能够保证当前券可被之前的所有物品使用,方便反悔操作。

发现 \(a_i-b_i\) 实质上就是优惠价给的满减值,我们维护一个堆存放当前可选的满减值,每次操作只有取或不取。若从堆中取了满减,那么将 \(a_i-b_i\) 加入堆。这个操作还挺好理解的,如果 \(a_i-b_i\) 在之后某次抉择中成了最优决策,那么将 \(i\) 用的券给当前物品用,然后 \(i\) 直接用优惠价买一定是优的。

然后就做完了,复杂度 \(\mathcal{O(n\log n)}\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define ppp pair<pii, pii>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
int n, m;
struct good{int a, b;} g[N];
struct rmm{int w, v;} c[N];
priority_queue<int, vector<int>, less<int> > q;
namespace Wisadel
{
    short main()
    {
        freopen("buy.in", "r", stdin), freopen("buy.out", "w", stdout);
        n = qr, m = qr;
        fo(i, 1, n) g[i].a = qr, g[i].b = qr;
        fo(i, 1, m) c[i].w = qr, c[i].v = qr;
        sort(g + 1, g + 1 + n, [](good A, good B){return A.a < B.a;});
        sort(c + 1, c + 1 + m, [](rmm A, rmm B){return A.w < B.w;});
        int j = 1; ll ans = 0;
        fo(i, 1, n)
        {
            while(j <= m && c[j].w <= g[i].a) q.push(c[j++].v);
            if(q.empty() || g[i].a - g[i].b >= q.top()) ans += g[i].b;
            else
            {
                ans += g[i].a - q.top(); q.pop();
                q.push(g[i].a - g[i].b);
            }
        }
        printf("%lld\n", ans);
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// 佳墙坂诶迦币等渔塞

C. IMAWANOKIWA (Construction ver.)

大粪掏题。

D. 魔法少女们

魔法题。

为什么只写了两个题就发,你是不是想摆烂?

因为 T1 打了一个下午,T3 看起来就要改很长时间,怕来不及记录就先发了。

谁问你了?

开场直接被隔壁发现是原题,甚至三天前的比赛直接搬。然后因为没人做过所以正常进行,输麻了。

状态?感觉不是,可能主要因为 T1 打了太久被影响了心态。其实 T1 当时已经打了正解的 \(\frac{3}{4}\) 左右了,考虑当时只剩一个半小时就没继续看,结果错误是弱智取模,输麻了。

T2 感觉也不该是想不出来的,不过丁真

image

T3 T4 压根不想看,感觉 T4 讲的优化是那种学了一辈子用不上几次的那种,粉兔讲题更是直言我卡你那个了就不会再卡这个,有点玄学。


完结撒花~

image

posted @ 2024-11-11 21:01  DrRatio  阅读(89)  评论(9编辑  收藏  举报