梦熊十三连测第三场题解

T1

本题考察了数论的相关知识。

30pts

暴力枚举每次洗牌的情况,时间复杂度为 O(n2)

60pts

首先卡牌 12n 一直不动,可以不用考虑这两张牌。

将位置和剩下的牌上的数字全减 1,那么数字为 k 的牌操作一次后就会到 2kmod(2n1) 的位置。

那么问题相当于找最小的 k 使得 t,t×2kt(mod(2n1)),显然只需要考虑 2k1(mod(2n1))​ 就行了,O(n) 暴力检验即可。

100pts

根据欧拉定理,k 必然是 φ(2n1) 的因数,而 1018 范围内的正整数的约数个数大约只有 106 级别,直接暴力快速幂判定就能过了。

输入的数会有点大。快读,开__int128

#include <bits/stdc++.h>
using namespace std;
#define int __int128
int n, m, p, t, e;
int T;
template<typename type>
inline void read(type &x)
{
    x=0;static bool flag(0);char ch=getchar();
    while(!isdigit(ch)) flag=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    flag?x=-x:0;
}

template<typename type>
inline void write(type x,bool mode=1)
{
    x<0?x=-x,putchar('-'):0;static short Stack[50],top(0);
    do Stack[++top]=x%10,x/=10; while(x);
    while(top) putchar(Stack[top--]|48);
    mode?putchar('\n'):putchar(' ');
}

int phi(int x) {
    int _p = x;
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            _p -= _p / i;
            while (x % i == 0) x /= i;
        }
    }
    if (x > 1)
        _p -= _p / x;
    return _p;
}
int ksm(int x, int y, int mod) {
    int a = x % mod;
    int ans = 1;
    while (y) {
        if (y & 1)
            ans *= a, ans %= mod;
        a *= a, a %= mod;
        y >>= 1;
    }
    return ans;
}
signed main() {
	freopen("card.in", "r", stdin);
	freopen("card.out", "w", stdout);
    read(T);
    while (T--) {
    	read(n);
        n = n - 1;
        m = 2 * n + 1;
        p = phi(m);
        t = p;
        e = sqrt((long long) p);
        for (int i = 1; i <= e; i++) {
			if(p%i!=0)continue;
            if (ksm(2, i, m) == 1) {
                t = i;
                break;
            }
			else {
                if (ksm(2, p / i, m) == 1)
                    t = p / i;
            }
        }
        write(t);
    }
    // fclose(stdin);
    // fclose(stdout);
    return 0;
}

T2

本题考察了图论的相关知识。

30pts

直接爆搜每次的情况并进行去重,时间复杂度为 O(n!),后续会给出具体证明。

+30pts

令初始的异或和为 x,拿在手中,相当于每次用手中的数把 a 中的一个值顶掉,然后把原来的值拿在手里,这也间接说明了状态数是 n! 量级的。

此档分会发现 ai 和所有 ai 异或后的权值两两不同,我们考虑一个过程,用 x 替换了 ap,然后用 ap 替换了 aq,循环下去。

其实最终一定是要用 bi 替换 ai 的,而上面的过程又是从 x 出发走了一条路,按如上方式建图找出环的个数即可统计答案。

100pts

我们从 biai 连边(不同位置上相同的数值对应同一个点),然后尝试从 x 出发遍历每条边。

注意如果图是一个包含 x 的连通块,则一定可以找到一条欧拉路径(不一定是回路)覆盖所有边。

如果图不连通,或 x 在连通块内(x 不是孤立点),则答案就是边数再加上连通块数再减去 1(如果 x 是孤立点就不用减 1)。

时间复杂度为 O(n)

T3

本题考察了树的直径,二分图的相关知识。

10pts

爆搜所有 2n 种情况,求最远点对距离即可。

40pts

考虑把 O(n2) 对点对依次取出排好序,考虑如果答案 <x,意味着所有点对距离 x 的点对颜色必须两两不同,把这些约束取出,相当于一个二分图染色的问题,于是我们可以很方便的算出 <x 的答案,利用差分即可算出 =x 的答案。

100pts

先求出一条直径,若直径的两个端点颜色相同,则最长距离一定为直径。否则,令两个端点分别为 x,y,并钦定 x,y 不同色。枚举答案 d,所有到 x 距离 >d 的点颜色必须与 y 一样,所有到 y 距离 >d 的点颜色必须和 x 一样。由于 x,y 是直径的两个端点,可以发现,若一个点 zx,y 的距离都不超过 d,则其到任何一个点的距离不超过 d,所以 z 的颜色并不会对答案产生影响。

所以,定义 cnti 表示到直径两端的距离不超过 i 的点数。定义 fd 表示答案不超过 d 的树的形态数,gd 表示答案为 d 的树的形态数,dis1/2 表示从直径的两端点出发到其他点的距离。定义L=max(min(dis1i,dis2i))。此处 L 的意义为,在所有形态的树中,最小的答案(同色点对最大距离)。对于每个点取到直径两端点近的那个颜色即可。

最终的总权值为 i=LSgi×i

容易得到 fd=2cntd。但是我们想要答案等于 d 的树的形态数 gi。很明显,只需要容斥减去 fd1 即可,也就是 gd=fdfd1

注意 x,y 共有 2 种颜色分配方案。

T4

本题考察了贪心的相关知识。

40pts

显然最终经过了 2k+dis(1,n) 条边,因此 (ndis(1,n))0(mod2) 就合法,否则不合法。

先考虑最小值,即只经过 path(1,n) 的方案。

那么对于路径上第 i 个点 ci,设他在路径外的子树大小为 siz(ci)

我们发现很多操作都要在折返中抵消,那么我们只要钦定链上哪些操作最终有用,剩下的操作形成若干跨子树的匹配,那么我们一定能构造一个合法的 p

根据经典结论,那么我们要求剩下的操作中不存在绝对众数。

找到最大的 siz(ci),那么我们至多在他的子树里钦定 i 个没被抵消。

因此这种情况的充要条件就是 siz(ci)i2ndis(1,n),显然这样的 i 至多一个,因此我们能构造出一个合法的匹配。

否则找到不合法的这棵子树,枚举一个连通块 S,记每个连通块内节点 u 在连通块外的子树大小为 siz(u)

那么我们依然要求 siz(u)i2ndis(1,n),证明大致同上。

那么我们要在这个基础上保留尽可能少的节点是的所有 siz(u) 不超过 k=2ndis(1,n)+i

问题就变成:给一棵 n 顶点的树,可以断掉若干的边,要求断掉的边连通且连通块包含 1 节点。要求剩下每个连通块大小不超过 k,求最小分割数,可以进行树形DP求解这个值,时间复杂度为 O(n2)

+10pts

考虑整张图为菊花图,所以除了 1 号点以外的地位相同,可以把除 n 号点的以外的点两两抵消,按照 n 的奇偶性进行分类讨论即可。

100pts

注意到 siz(ci)ndis(1,n)2k,因此不合法的所有点构成一条链,对于每个点贪心地割掉若干个最大的子树即可。

时间复杂度 O(nlogn),如果利用桶排序,时间复杂度为 O(n)

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