首页 > 其他分享 >Solution Set 2023.12.14

Solution Set 2023.12.14

时间:2023-12-14 14:59:16浏览次数:36  
标签:Set const 2023.12 valueType Solution T1 right mod left

CF698F Coprime Permutation

考虑 \(p_i = 0\) 的情况下怎么做,首先排列 \(p_i = i\) 一定符合条件,考虑在此基础上生成其他符合要求的排列,考虑什么情况下 \(p_i\) 和 \(p_j\) 可以互换,发现其可以互换当且仅当对于所有 \(x \neq i\) 且 \(x \neq j\),均有 \(\left[\gcd\left(i, x\right) = 1\right] = \left[\gcd\left(j, x\right) = 1\right]\)。可以发现若 $i, j \(i, j\) 的质因子集合相同,那么一定可以交换。

设 \(w_{x}\) 表示 \(x\) 的本质不同质因子的乘积(例如 \(w_{8} = 2, w_{24} = 6\)),\(f_{k} = \sum\limits_{1 \le i \le n}\left[w_i = k\right]\)。那么可以发现至此一共有 \(\prod f_i!\) 种交换方案。

考虑质因子集合不同的情况是否可以置换,发现若存在质数 \(p_1, p_2\),满足 \(\forall i, \left[i \times p_1 \le n\right] = \left[i \times p_2 \le n\right]\),那么可以发现将所有的 \(k \times p_1\) 和 \(k \times k_2\) 调换位置后排列也一定合法。上述条件可以简化为 \(\left\lfloor\dfrac{n}{p_1}\right\rfloor = \left\lfloor\dfrac{n}{p_2}\right\rfloor\)。

设 \(g_k = \sum\limits_{1 \le i \le n} \left[\left\lfloor\dfrac{n}{i}\right\rfloor = k\right]\)。那么综上我们可以得出一共有 \(\prod f_i! \times \prod g_i!\) 种方案。

接下来考虑存在 \(p_i != 0\) 的情况。可以发现 \(p_i\) 被指定,那么其所属的质因子集合会减少一个可用于交换的元素,另外其还有可能直接指定两个质数间的交换关系。

对于前者的处理是平凡的,将用于统计质因子集合对应元素数量的桶的值减一即可。

对于后者的处理,首先我们需要找出可能会被交换的质因子。根据整除分块的结论,我们可以得出若存在 \(i \neq j\),使得 \(\left\lfloor\dfrac{n}{i}\right\rfloor = \left\lfloor\dfrac{n}{j}\right\rfloor\),那么一定有 \(i, j \ge \sqrt{n}\),而大于 \(\sqrt{n}\) 的质因子每个数最多可能有一个,因此我们直接提取 \(i\) 和 \(p_i\) 的最大质因子进行判断即可,不妨设为 \(x, y\)。若其两者的质数集去除 \(x, y\) 后不同,那么无解。

首先我们需要判断是否满足 \(\left\lfloor\dfrac{n}{x}\right\rfloor = \left\lfloor\dfrac{n}{y}\right\rfloor\),若不满足那么无解。

接下来需要判断 \(x, y\) 是否已经被指定了交换关系。需要注意这里的交换关系是单向的,即 \(x \rightarrow y\),可以理解为将下标中的所有 \(x\) 质因子替换为 $。因为此类交换关系最终一定会形成若干个环,但是环长并不一定为 \(2\)。所以我们需要对交换关系形成的有向图和其反向图存储下来并加以判断。若冲突则无解,否则其对应的 \(g\) 值也需要相应减少 \(1\)。

总复杂度为 \(\mathcal{O}(n \log n)\),瓶颈在于分解质因子。

Code
  #include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

namespace MODINT {
    constexpr valueType MOD = 1e9 + 7;

#define ModOperSafeModOption false

    template<typename T1, typename T2, typename T3 = valueType>
    void Inc(T1 &a, T2 b, const T3 &mod = MOD) {
        a = a + b;

        if (a >= mod)
            a -= mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    void Dec(T1 &a, T2 b, const T3 &mod = MOD) {
        a = a - b;

        if (a < 0)
            a += mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 sum(T1 a, T2 b, const T3 &mod = MOD) {
        return a + b >= mod ? a + b - mod : a + b;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 sub(T1 a, T2 b, const T3 &mod = MOD) {
        return a - b < 0 ? a - b + mod : a - b;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 mul(T1 a, T2 b, const T3 &mod = MOD) {
        return (long long) a * b % mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    void Mul(T1 &a, T2 b, const T3 &mod = MOD) {
        a = (long long) a * b % mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 pow(T1 a, T2 b, const T3 &mod = MOD) {
        T1 result = 1;

        while (b > 0) {
            if (b & 1)
                Mul(result, a, mod);

            Mul(a, a, mod);
            b = b >> 1;
        }

        return result;
    }
}// namespace MODINT

using namespace MODINT;

class LineSieve {
public:
    typedef ValueVector container;

private:
    valueType size;
    container minFactorList;
    container primeList;

public:
    explicit LineSieve(valueType _size_) : size(_size_), minFactorList(_size_ + 1) {
        for (valueType i = 2; i <= size; ++i) {
            if (minFactorList[i] == 0) {
                primeList.push_back(i);
                minFactorList[i] = i;
            }

            for (auto const &iter : primeList) {
                valueType const t = i * iter;

                if (t > size)
                    break;

                minFactorList[t] = iter;

                if (i % iter == 0)
                    break;
            }
        }
    }

    valueType lpf(valueType x) const {
        if (x > size)
            throw std::range_error("Larger than Size.");

        if (x < 1)
            throw std::range_error("Too small.");

        return minFactorList[x];
    }

    bool isPrime(valueType x) const {
        if (x > size)
            throw std::range_error("Larger than Size.");

        if (x < 1)
            throw std::range_error("Too small.");

        return minFactorList[x] == x;
    }

    const container &getPrime() const {
        return primeList;
    }
};

void failed() {
    std::cout << 0 << std::endl;

    std::exit(0);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType N;

    std::cin >> N;

    LineSieve const sieve(N);

    ValueVector P(N + 1, 0);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> P[i];

    ValueVector primeSetMul(N + 1, 1), primeSetCount(N + 1, 0);
    ValueMatrix primeSet(N + 1);

    for (valueType i = 2; i <= N; ++i) {
        valueType x = i;

        while (x > 1) {
            valueType const p = sieve.lpf(x);

            primeSet[i].emplace_back(p);
            primeSetMul[i] *= p;

            while (x % p == 0)
                x /= p;
        }

        ++primeSetCount[primeSetMul[i]];
    }

    primeSet[1].emplace_back(1);
    ++primeSetCount[1];

    ValueVector divide(N + 1, 0), divideCount(N + 1, 0);

    for (auto const &p : sieve.getPrime()) {
        divide[p] = N / p;

        ++divideCount[divide[p]];
    }

    divide[1] = 1;
    ++divideCount[1];

    ValueVector index2value(N + 1, 0), value2index(N + 1, 0);

    for (valueType i = 1; i <= N; ++i) {
        if (P[i] == 0)
            continue;

        if (primeSet[P[i]].size() != primeSet[i].size())
            failed();

        for (valueType j = 0; j + 1 < primeSet[P[i]].size(); ++j) {
            if (primeSet[P[i]][j] != primeSet[i][j])
                failed();
        }

        valueType const indexPrime = primeSet[i].back(), valuePrime = primeSet[P[i]].back();

        if (divide[valuePrime] != divide[indexPrime])
            failed();

        if (index2value[indexPrime] != 0 && index2value[indexPrime] != valuePrime)
            failed();

        if (value2index[valuePrime] != 0 && value2index[valuePrime] != indexPrime)
            failed();

        if (index2value[indexPrime] == 0 && value2index[valuePrime] == 0)
            --divideCount[divide[valuePrime]];

        index2value[indexPrime] = valuePrime;
        value2index[valuePrime] = indexPrime;

        --primeSetCount[primeSetMul[P[i]]];
    }

    ValueVector Fact(N + 1, 0);

    Fact[0] = 1;
    for (valueType i = 1; i <= N; ++i)
        Fact[i] = mul(Fact[i - 1], i);

    valueType ans = 1;

    for (valueType i = 1; i <= N; ++i)
        Mul(ans, Fact[primeSetCount[i]]);

    for (valueType i = 1; i <= N; ++i)
        Mul(ans, Fact[divideCount[i]]);

    std::cout << ans << std::endl;

    return 0;
}

标签:Set,const,2023.12,valueType,Solution,T1,right,mod,left
From: https://www.cnblogs.com/User-Unauthorized/p/2023-12-14.html

相关文章

  • 2020CVPR_High-Resolution Image Synthesis with Latent Diffusion Models
    1.AutoEncoderAutoEncoder(自编码器)是一种无监督学习的神经网络模型,用于学习有效的数据表示。它的目标是将输入数据编码成一种潜在的、紧凑的表示形式,然后从这个表示中重构原始输入。自编码器由两部分组成:编码器(Encoder)和解码器(Decoder)。编码器(Encoder):将输入数据映射到潜在表示空......
  • 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.14)
    一、百度网盘SVIP超级会员共享账号可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答。我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免了U盘的物理载体,直接在网上就实现文件传输。百度网盘SVIP会员可以让自己百度账......
  • 【笔记】2023.12.14 树上问题
    笔记2023.12.14:树上问题[Ynoi2004]rpmtdq支配对:\(i_1\leqi_2\leqj_2\leqj_1,dist(i_1,j_1)\geqdist(i_2,j_2)\)时,称\((i_1,j_1)\)被\((i_2,j_2)\)支配,前者就无用了,选到区间只要包含\((i_1,j_1)\)就一定包含\((i_2,j_2)\)。点分治到\(rt\)时,记\(d_x=dis......
  • Java之Hashset的原理及解析
     4.数据结构4.1二叉树【理解】二叉树的特点二叉树中,任意一个节点的度要小于等于2节点:在树结构中,每一个元素称之为节点度:每一个节点的子节点数量称之为度二叉树结构图编辑4.2二叉查找树【理解】二叉查找树的特点二叉查找树,又称二叉排序树或者二叉搜索树每一个节点上最多有两......
  • 2023.12.12 校赛解题报告
    7-1点菜题面Congruent和ComistryMo两个人正在饭店吃饭,饭店里面一共有\(n\)道菜,每道菜有一个价格\(a_i\)​\((1≤i≤n)\)。他俩会在饭店按顺序点\(k\)道菜(可以不连续,保证相对顺序即可),假设点的菜序列为\(S_1−S_k\)。他们约定:一个人付所有奇数下标已点菜品价格的最大......
  • 2023.12.13日报
    最近事情比较多,写日报也有点怠惰了,主要是偶尔会忘记,简单总结一下这两天的工作首先是使用jfinal做大作业,实话说这玩意一开始我觉得并不好用,因为页面也很简陋,后端也有点看不懂但是在实际体验并且调用百度翻译和图像处理的api后,感觉用起来还可以,其实和springboot有点类似现在是已......
  • ArgoCD ApplicationSet CRD
    ApplicationSet概述ApplicationSetcontroller是一个Kubernetescontroller,添加了对ApplicationSetCustomResourceDefinition(CRD)的支持。该controller/CRD实现了跨大量集群和monorepos内管理ArgoCDApplication的自动化和更大的灵活性,此外,它还使多租户Kubernetes......
  • 除了Promise.all(),使用Promise.allSettled()方式请求,避免使用循环请求
    constgetFilePromises:Promise<any>[]=[];fileIds.forEach((item)=>{getFilePromises.push(getFileInfoApi({id:item}));});Promise.allSettled(getFilePromises).then((res)=>{this.fileList=res.map((item,index)=>......
  • Solution Set 2023.12.13
    CF1736ESwapandTake设在第\(i\)次操作后产生贡献的值为初始序列的\(a_{p_i}\),可以发现产生的贡献的指针移动方式为每次向后移动\(1\),而通过交换数字最多可以使得某个数字每次向后移动\(1\),由此可以得出每次产生贡献的位置单调不减,即\(p_1\lep_2\le\cdots\lep_n\)......
  • vulkan/descriptorSet
    参考Shaderlayout(binding=0)uniformUniformBufferObject{mat4model;mat4view;mat4proj;}ubo;layout(location=0)invec2inPosition;layout(location=1)invec3inColor;layout(location=2)invec2inTexCoord;layout(location=0)......