• [NOI 2015]寿司晚宴


    Description

    题库链接

    给定 (2sim n) 一共 (n-1) 个数字,第一个人选择一些数字,第二个人选择一些数字,要求第一个人选的任意一个数字和第二个人选择的任意一个数字都互质,求方案数。

    (2leq nleq 500)

    Solution

    做的时候想偏了...正解做法比较神...

    我们考虑对一个数质因数分解,容易发现对于 (geq sqrt{500}) 的质因数一定最多一个。

    我们可以拿 (geq sqrt{500}) 的质因数为依据分组。对于 (leq sqrt{500}) 的质因数一共只有 (8) 个,我们拿来状压。

    如果一个数没有 (geq sqrt{500}) 的质因数,那么它单独成一组。

    显然的是同一组的数不能同一个人拿,因为同一组共同拥有一个 (geq sqrt{500}) 的质因数(或没有)。

    所以我们可以按组来做。

    (f_{i,j}) 表示第一个人选 (leq sqrt{500}) 的质因数的状态为 (i) ,第二个人为 (j) 的方案数,显然 (icap j=0)

    那么考虑组内 ( ext{DP}) 。记 (f_{0/1,i,j}) 表示第一/二个人选这一组(或是不选)第一个人选 (leq sqrt{500}) 的质因数的状态为 (i) ,第二个人为 (j) 的方案数。

    首先先将 (f) 分别拷一份给 (g_{0},g_{1})

    组内 ( ext{DP}) 后再将 (f'=g_{0}+g_{1}-f) ,因为都不选的方案算了两次。

    最后统计答案即可。

    Code

    #include <bits/stdc++.h>
    #define ll long long
    #define pii pair<int, int>
    using namespace std;
    const int prime[8] = {2, 3, 5, 7, 11, 13, 17, 19};
    const int N = 505, SZ = (1<<8)+5;
    
    int n, bin[10];
    ll p, f[SZ][SZ], g[2][SZ][SZ];
    pii a[N];
    
    void work() {
        scanf("%d%lld", &n, &p);
        bin[0] = 1;
        for (int i = 1; i <= 8; i++) bin[i] = (bin[i-1]<<1);
        for (int i = 2; i <= n; i++) {
            int x = i;
            for (int j = 0; j < 8; j++) {
                if (x%prime[j] == 0) a[i].second |= bin[j];
                while (x%prime[j] == 0) x /= prime[j];
            }
            a[i].first = x;
        }
        sort(a+2, a+n+1); f[0][0] = 1;
        for (int i = 2; i <= n; i++) {
            if (a[i].first == 1 || a[i].first != a[i-1].first)
                memcpy(g[0], f, sizeof(g[0])), memcpy(g[1], f, sizeof(g[1]));
            for (int j = bin[8]-1; ~j; j--)
                for (int k = bin[8]-1; ~k; k--) {
                    if ((a[i].second&k) == 0)
                        (g[0][j|a[i].second][k] += g[0][j][k]) %= p;
                    if ((a[i].second&j) == 0)
                        (g[1][j][k|a[i].second] += g[1][j][k]) %= p;
                }
            if (a[i].first == 1 || a[i].first != a[i+1].first) {
                for (int j = 0; j < bin[8]; j++)
                    for (int k = 0; k < bin[8]; k++)
                        f[j][k] = (g[0][j][k]+g[1][j][k]-f[j][k])%p;
            }
        }
        ll ans = 0;
        for (int j = 0; j < bin[8]; j++)
            for (int k = 0; k < bin[8]; k++)
                (ans += f[j][k]) %= p;
        printf("%lld
    ", (ans+p)%p);
    }
    int main() {work(); return 0; }
  • 相关阅读:
    Eclipse安装Pydev插件时所遇到的问题
    打开Eclipse弹出“No java virtual machine was found..."的解决方法
    使用adb报错;error: unknown host service
    itools安装程序无法创建临时文件夹
    多线程十二之ConcurrentHashMap1.8实现分析
    多线程十一之ConcurrentHashMap1.7源码分析
    多线程十之CopyOnWriteArrayList源码分析
    多线程学习笔记九之ThreadLocal
    多线程学习笔记八之线程池ThreadPoolExecutor实现分析
    多线程学习笔记七之信号量Semaphore
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/9253780.html
Copyright © 2020-2023  润新知