CW 11.13 模拟赛 个人记录

T1

算法

暴力

暴力思路是显然的, 观察到并查集可以 \(\mathcal{O}(n \log n)\) 的维护题目中求的信息
对于 \(50\%\) 的数据显然可以通过

耗时 \(10 \rm{min}\) , 正常

正解

暴力疑似就是正解 ?????

代码

这个题只要挂了我就趋势, 但是看这样子来说应该是 \(T1\) 放了简单题

不挂的话可以保 \(100 \rm{pts}\) , 应该是稳的

#include <bits/stdc++.h>
#define int long long
const int MAXN = 1e5 + 20;

int n;
int Val[MAXN];

int m;
int u, v;

struct Union_Set_Struct
{
    int fa[MAXN];
    void fa_init()
    {
        for (int i = 1; i <= n; i++)
            fa[i] = i;
    }
    int find(int x) { return fa[x] = (x == fa[x]) ? x : find(fa[x]); }

    void merge(int u, int v)
    {
        int Led_u = find(u), Led_v = find(v);
        if (Led_u == Led_v)
        {
            printf("%lld\n", Led_v);
            return;
        }

        if (Val[Led_u] > Val[Led_v])
            fa[Led_v] = Led_u, printf("%lld\n", Led_u);
        else
            fa[Led_u] = Led_v, printf("%lld\n", Led_v);
    }
} Union_Set;

signed main()
{
    freopen("company.in", "r", stdin);
    freopen("company.out", "w", stdout);

    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &Val[i]);

    scanf("%lld", &m);
    Union_Set.fa_init();
    while (m--)
    {
        scanf("%lld %lld", &u, &v);
        Union_Set.merge(u, v);
    }

    return 0;
}

总结

啊?

T2

前言

别死磕, 别畏难, 别管别人!!!

时间分配

先打暴力

做好对拍

根据 \(\rm{Subtask}\) 推做法

不要慌

记得检查

做好笔记 (今天的打法非常好)

不是这题怎么给 \(70 \rm{pts}\) 的部分分啊???

希望做法是真的 ( \(\rm{WC}\) 对了一下大概是好的 )

算法

\(\rm{Subtask}\) 1

模拟王启动

对于 \(30\%\) 的数据非常好打

\(\rm{Subtask}\) 2

\(a_i = 1\) , 标准找 \(\rm{lcm}\) , 提示了一下做法

\(\rm{Subtask}\) 3

\(n = 1\) , 只有一个玻璃框 , 也是提示

正解

讲真 \(\rm{Subtask} \text{ } 2, 3\) 推出来就有了

手玩样例, 有一道之前的题倒是很像

观察到问题可以转化为求一个字符串的最短循环节问题,

这是 KMP 的一个典型应用, 可以用 \(\mathcal{O}(n)\) 的时间复杂度解决


考虑流程如下

读入 \(\to\) 处理每个字符串的最短循环节 \(\to\) 问题转化为求

\(\text{最短循环节长度 } \mid a_i \times k \text{ } \rm{s.t} \text{ } k \to min\)


现在我们已知每个字符串最少要 \(k_i\) 次才能回到原先的模样

对于所有 \(k_i\) , 求其最小公倍数即可

代码

讲个笑话, 我在考场上写博客... (是的, 这些思路都是记录考场口胡的)

先看一下 KMP 求最短循环节的代码还会不会写

在这里提前想组数据, 造福几十分钟后的我

in:
3
5 11 7
abcabcabcabc
fhdsijgfhdsijg
yangxiaobao

out:
231

这应该挺平凡吧, 不会再被诈骗了

这个时候要赌一把了 开考 \(2 h\) 想保住 \(170 \rm{pts}\) 还需要打数据点分治

赌一手后面分更多 + 我代码不挂

赌输了可能要爆零

关于 KMP

class Shortest_Loop_Class
{
private:
    int Next[MAXLEN];
    void getNext(int p, int plen)
    {
        memset(Next, 0, sizeof(Next));
        Next[0] = 0, Next[1] = 0;
        for (int i = 1; i < plen; i++) {
            int j = Next[i];
            while (j && str[p][i] != str[p][j])
                j = Next[j];
            if (str[p][i] == str[p][j]) Next[i + 1] = j + 1;
            else Next[i + 1] = 0;
        }
    }

public:
    int Len[MAXN];
    void solve()
    {
        for (int i = 1; i <= n; i++) {
            int NowLen = str[i].length();
            getNext(i, NowLen);
            Len[i] = (NowLen % (NowLen - Next[NowLen]) == 0) ? (NowLen - Next[NowLen]) : NowLen;
        }
        return;
    }
} Shortest_Loop;

\(20 \rm{min}\) 过去了, 我 KMP 挂了, 寄

记得开 \(\rm{long} \text{ } \rm{long}\)

总的代码

#include <bits/stdc++.h>
#define int long long
const int MAXN = 15;
const int MAXLEN = 1e5 + 20; // 641

#define lcm(a, b) a / std::__gcd(a, b) * b

int n;
int a[MAXN];

std::string str[MAXN];

class Shortest_Loop_Class
{
private:
    int Next[MAXLEN];
    void getNext(int p, int plen)
    {
        memset(Next, 0, sizeof(Next));
        Next[0] = 0, Next[1] = 0;
        for (int i = 1; i < plen; i++) {
            int j = Next[i];
            while (j && str[p][i] != str[p][j])
                j = Next[j];
            if (str[p][i] == str[p][j]) Next[i + 1] = j + 1;
            else Next[i + 1] = 0;
        }
    }

public:
    int Len[MAXN];
    void solve()
    {
        for (int i = 1; i <= n; i++) {
            int NowLen = str[i].length();
            getNext(i, NowLen);
            Len[i] = (NowLen % (NowLen - Next[NowLen]) == 0) ? (NowLen - Next[NowLen]) : NowLen;
        }
        return;
    }
} Shortest_Loop;

int k[MAXN];

signed main()
{
    freopen("tiger.in", "r", stdin);
    freopen("tiger.out", "w", stdout);
    
    scanf("%lld", &n);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    for (int i = 1; i <= n; i++)
        std::cin >> str[i];

    Shortest_Loop.solve();

    for (int i = 1; i <= n; i++)
        k[i] = lcm(Shortest_Loop.Len[i], a[i]) / a[i];

    int Ans = 1;
    for (int i = 1; i <= n; i++)
        Ans = lcm(Ans, k[i]);
    printf("%lld", Ans);

    return 0;
}

总结

多见些题总是好的

前言里的东西好好记住

\(\rm{Subtask}\) 推正解大法好

T3

前言

考试还有 \(50 \rm{min}\), 只能拼点暴力上去

已经结束咧

算法

讲真看着好像可做啊

这套题还挺好的, 遗憾

感觉 \(\rm{lhs}\) 又要 \(\rm{AK}\) 了 , 只剩下一个小时了

暴力

选点的方式是一定的, 枚举两两之间的点, 再简单的计算一下路径种类数

\(20\%\)\(\rm{Subtask}\) 相当于提示你算基础的

对于点 \((x_1, y_1) \to (x_2, y_2)\) 的路径数计算

有横向移动次数 \(a = \lvert{x_2 - x_1\rvert}\) , 纵向移动次数 \(b = \lvert{y_2 - y_1\rvert}\)

穿插加入即可

种类数为 $Ans = \frac{(a + b)!}{a! \times b!} $

观察到直到 \(60\%\) 的数据都有起始点一定, 但是终点的数量级导致我应该只能拼上去一个 \(40 \rm{pts}\)

代码

#include <bits/stdc++.h>
#define int long long
const int MOD = 998244353;

int T;
int X1a, Y1a, X1b, Y1b, X2a, Y2a, X2b, Y2b;

/*起始点恒定, 终点为一条线*/
class Subtask_AB_Class
{
private:
    int Mul(int x)
    {
        int Ans = 1;
        for (int i = x; i >= 1; i--)
            Ans *= i, Ans %= MOD;
        return Ans;
    }
    int quickpow(int x, int p)
    {
        int base = x % MOD;
        int Ans = 1;
        while(p) {
            if(p & 1) Ans %= MOD, Ans *= base, Ans %= MOD;
            base = base * base % MOD;

            p >>= 1;
        }

        return Ans % MOD;
    }

public:
    int Ans = 0;
    void solve()
    {
        Ans = 0;
        for (int i = X2a; i <= X2b; i++)
        {
            int a = abs(i - X1a), b = abs(Y2a - Y1b);

            Ans += Mul(a + b) / (Mul(a) * Mul(b));
            Ans %= MOD;
        }

        printf("%lld\n", Ans);
    }
} Subtask_AB;

signed main()
{
    freopen("rectangle.in", "r", stdin);
    freopen("rectangle.out", "w", stdout);

    scanf("%lld", &T);
    while(T--) {
        scanf("%lld %lld %lld %lld %lld %lld %lld %lld", &X1a, &Y1a, &X1b, &Y1b, &X2a, &Y2a, &X2b, &Y2b);

        Subtask_AB.solve();
    }

    return 0;
}

正解

只能考完之后补了

总结

妈妈生的

T4

前言

打到这里只有 \(13 \rm{min}\)
拼不动了

算法

暴力

只有 \(1\) 号地点放置宝箱 / 钥匙的 \(40 \rm{pts}\) 应该能做

本质上就是求遍历所有点在绕回来的最短路径

没打出来呜呜呜呜

正解

回来补

总结

阿米诺斯

这次部分分挺足的, 寄!

盲猜倒数

posted @ 2024-11-13 14:47  Yorg  阅读(1)  评论(0编辑  收藏  举报