2024.10.16 CW 模拟赛

题目链接:https://files.cnblogs.com/files/blogs/833333/CW1016.zip?t=1729123549&download=true

T2 (CF1101D)

算法:\(dfs\) 求直径,\(MIller\_Rabin\) 判断素数(可用可不用,但不用会 \(wrong\ answer\) ,不知道为什么

阅读题目,旨在让我们求一条 \(gcd\) 不等于 \(1\) 的一条最长链。\

容易知道如果一条链上所有数的 \(gcd\) 不为一,那么其一定有共同的质因数。\

所以可以想到把有相同质因子的点放在一起处理,再在每个连通块里面求一次树的直径就行了。\

最后如果点权全是 \(1\) ,须要特判输出 \(0\)

CODE

#include "iostream"
#include "cstdio"
#include "vector"
#include "bits/extc++.h"

using namespace std;
using namespace __gnu_pbds;

// char buf[1 << 20], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? 0 : *p1++)
template <typename T>
inline void read(T &x)
{
    bool f = 1;
    x = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = !f;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x = (f ? x : -x);
    return;
}

template <typename T>
inline void write(T x)
{
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
    return;
}

const int N = 2e5 + 10;

int cnt = 0, p[N];
bool is_prime[N];

inline void calculate_prime()
{
    is_prime[1] = 1;
    for (int i = 2; i <= 50000; ++i)
    {
        if (!is_prime[i])
            p[++cnt] = i;
        for (int j = 1; j <= cnt and p[j] * i <= 50000; ++j)
        {
            is_prime[p[j] * i] = 1;
            if (!(i % p[j]))
                break;
        }
    }
    return;
}

int n, a[N], dis[N], q[N];
int z[N];
bool vis[N];
int tail;
int Mod, A[11] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 61};
vector<int> tr[N];
cc_hash_table<int, vector<int>> mp;
cc_hash_table<int, int> t;

int quickpower(int x, int y)
{
    int ans = 1, op = x;
    while (y)
    {
        if (y & 1)
            ans *= op, ans %= Mod;
        op *= op, op %= Mod;
        y >>= 1;
    }
    return ans;
}

inline bool judge_prime(int x)
{
    Mod = x;
    int s = 0;
    if (x == 2)
        return 1;
    if (x % 2 == 0 || x == 1)
        return 0;
    int p = x - 1;
    while (p % 2 == 0)
        p /= 2, s++;
    for (int j = 1; j <= 5; j++)
    {
        int B = quickpower(A[j], p);
        for (int i = 1; i <= s; i++)
        {
            int K = (B * B) % Mod;
            if (K == 1ll && B != 1ll && B != Mod - 1)
                return 0;
            B = K;
        }
        if (B != 1ll)
            return 0;
    }
    return 1;
} //不知为什么不用这个会错,故加上

void dfs(int nw, int prime, int fa)
{
    vis[nw] = 1;
    q[++tail] = nw;
    dis[nw] = dis[fa] + 1;
    for (int to : tr[nw])
    {
        if (to == fa)
            continue;
        if (!(a[to] % prime))
            dfs(to, prime, nw);
    }
    return;
}

inline int calculate_longest(int nw, int prime)
{
    tail = 0;
    int ans = 0;
    vis[nw] = 1;
    dfs(nw, prime, 0);
    int f = 0;
    for (int i = 1; i <= tail; ++i)
        if (dis[q[i]] > dis[f])
            f = q[i];
    for (int i = 1; i <= tail; ++i)
        dis[q[i]] = 0;

    tail = 0;
    dfs(f, prime, 0);
    f = 0;
    for (int i = 1; i <= tail; ++i)
        if (dis[q[i]] > dis[f])
            f = q[i];

    return dis[f];
}

int main()
{

    calculate_prime();

    read(n);
    for (int i = 1; i <= n; ++i)
        read(a[i]);

    for (int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d %d", &u, &v);
        tr[u].push_back(v);
        tr[v].push_back(u);
    }

    cnt = 0;
    for (int i = 1; i <= n; ++i)
    {
        int x = a[i];
        bool fl = judge_prime(x);
        if (fl)
        {
            mp[x].push_back(i);
            if (t[x] != 1)
                t[x] = 1, z[++cnt] = x;
            continue;
        }
        for (int j = 1; p[j] * p[j] <= x; ++j)
            while (!(x % p[j]))
            {
                x /= p[j], mp[p[j]].push_back(i);
                if (!t[p[j]])
                    t[p[j]] = 1, z[++cnt] = p[j];
            }
        if (x != 1)
        {
            mp[x].push_back(i);
            if (t[x] != 1)
                t[x] = 1, z[++cnt] = x;
        }
    }

    int ans = 1;
    for (int i = 1; i <= cnt; ++i)
    {
        for (int x : mp[z[i]])
            if (!vis[x])
                ans = max(ans, calculate_longest(x, z[i]));
        for (int x : mp[z[i]])
            vis[x] = dis[x] = 0;
    }

    for (int i = 1; i <= n; ++i)
        if (a[i] != 1)
            return write(ans), 0;

    write(0);

    return 0;
}


T3 (CF962E)

一道构造题。
画画图可以发现,无非就两种决策:

  • 1.\(P,B\ or\ P,R\) 之间依次连边
  • 2.相邻的 \(P\) 之间连边(作为 \(B\)\(R\)\(P\) 连通图的公用边)

最后相邻的 \(P\) 之间 \(B\)\(R\) 单独连边。(中间一条最大边可以去掉)

#include "iostream"

using namespace std;

#define int long long

int n, ans;
int d = 0, p = 0, f = 0, v = 0, g = 0;
bool flr = 0, flb = 0, flp = 0;

signed main()
{

    cin >> n;

    for (int i = 1; i <= n; i++)
    {
        int x;
        char c;
        cin >> x >> c;
        if (c == 'P' or c == 'R')
        {
            if (flr)
                ans += (x - d), p = max(p, x - d);
            flr = 1, d = x;
        }
        if (c == 'P' or c == 'B')
        {
            if (flb)
                ans += (x - f), v = max(v, x - f);
            flb = 1, f = x;
        }
        if (c == 'P')
        {
            if (flp)
                ans += min(0ll, x - g - v - p);
            flp = 1, p = v = 0, g = x;
        }
    }

    cout << ans << endl;

    return 0;
}

T4

正解:最短路,状压 \(dp\)

  • 对于20%的数据,\(n \le 300,k \le 10\)

将起点与特殊点都称为关键点

\(Floyd\) 计算出关键点之间及每个关键点到任意一个终点的最小距离,然后搜索即可

复杂度 \(\mathcal{O}(n^3+k!)\)

  • 对于50%的数据,\(n \le 1000,k \le 10\)
    改用 \(dijkstra\) 算法,枚举所有关键点为起点的单源最短路 \(\mathcal{O}(kn^2+k!)\)

  • 对于70%的数据,\(k \le 20\)
    考虑状压 \(dp\).
    \(f_{i,S}\) 表示当前经过的关键点集合为 \(S\) ,最终到达 \(i\) 点进过的最短距离, 用二进制数表示集合(状态压缩).
    复杂度 \(\mathcal{O}(km \log m+k^2*2^k)\).

#include "iostream"
#include "cstdio"
#include "cstring"
#include "vector"
#include "queue"

using namespace std;

#define lowbit(x) (x & -x)
typedef pair<int, int> pii;
typedef long long ll;

template <typename T>
inline void read(T &x)
{
    bool f = 1;
    x = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = !f;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x = (f ? x : -x);
    return;
}

const int N = 5e4 + 10, M = 20;

int n, m, k, s;
int d[N], p[N];
vector<pii> g[N]; // 输入
ll dis[N], f[M][1 << M];
ll a[M][M], v[M], sz[1 << M];
bool vis[N];
deque<int> q;

inline void spfa(int s)
{
    for (int i = 1; i <= n; ++i)
        dis[i] = 1e18, vis[i] = 0;
    dis[s] = 0;
    q.push_back(s);
    vis[s] = 1;
    while (!q.empty())
    {
        int nw = q.front();
        q.pop_front();
        vis[nw] = 0;
        for (auto to : g[nw])
        {
            if (dis[to.first] > dis[nw] + to.second)
            {
                dis[to.first] = dis[nw] + to.second;
                if (!vis[to.first])
                {
                    if (!q.empty() and dis[to.first] < dis[q.front()])
                        q.push_front(to.first);
                    else
                        q.push_back(to.first);
                    vis[to.first] = 1;
                }
            }
        }
    }
    return;
}

int main()
{

    read(n), read(m), read(k), read(s);
    for (int i = 1; i <= n; ++i)
        read(p[i]);
    for (int i = 1; i <= m; ++i)
    {
        int u, v, w;
        read(u), read(v), read(w);
        g[u].emplace_back(v, w);
        g[v].emplace_back(u, w);
    }
    for (int i = 0; i < k; ++i)
        read(d[i]);

    for (int i = 0; i < k; ++i)
    {
        spfa(d[i]);
        f[i][1 << i] = dis[s];
        v[i] = 1e18;
        for (int j = 1; j <= n; ++j)
            if (p[j])
                v[i] = min(v[i], dis[j]);
        for (int j = 0; j < k; ++j)
            a[i][j] = dis[d[j]];
    }

    for (int w = 1; w < (1 << k); ++w)
    {
        sz[w] = sz[w - lowbit(w)] + 1;
        if (!(w - lowbit(w)))
            continue;
        for (int i = 0; i < k; ++i)
        {
            f[i][w] = 1e18;
            if (!((w >> i) & 1))
                continue;
            for (int j = 0; j < k; ++j)
                if (i != j and (w >> j) & 1)
                    f[i][w] = min(f[i][w], f[j][w - (1 << i)] + a[i][j] * sz[w]);
        }
    }

    ll ans = 1e18;
    for (int i = 0; i < k; ++i)
        ans = min(ans, f[i][(1 << k) - 1] + v[i] * (k + 1));

    printf("%lld", ans);

    return 0;
}
posted @   Steven1013  阅读(2)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示