标签: 卡常

  • 洛谷2396 yyy loves Maths VII

    又是一道包题。

    直接状压DP即可。

    注意一下常数优化

    // luogu-judger-enable-o2
    #include <iostream>
    
    using int_t = unsigned int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 1e9 + 7;
    
    inline int_t lowbit(int_t x)
    {
        return x & (-x);
    }
    
    int_t arr[30];
    int_t dp[1 << 24];
    // int_t sum[1 << 20];
    int_t to[1 << 24];
    int_t n, m;
    int_t bad[4];
    char bit[1 << 24];
    int main()
    {
        cin >> n;
        for (int_t i = 0; i < n; i++)
            cin >> arr[i];
        cin >> m;
        for (int_t i = 0; i < m; i++)
            cin >> bad[i];
        for (int_t i = 0; i < 24; i++)
            bit[1 << i] = i;
        for (int_t i = 1; i < (1 << n); i++)
        {
            to[i] = to[i - lowbit(i)] + arr[bit[lowbit(i)]];
            if (to[i] == bad[0] || to[i] == bad[1])
                dp[i] = -1;
        }
        dp[0] = 1;
        for (int_t i = 1; i < (1 << n); i++)
        {
            if (dp[i] == -1)
            {
                dp[i] = 0;
                continue;
            }
            int_t curr = i;
            while (curr)
            {
                int_t bit = lowbit(curr);
    
                dp[i] = (dp[i] + dp[i ^ bit]);
                dp[i] -= (dp[i] > mod) ? mod : 0;
                curr -= bit;
            }
        }
        cout << dp[(1 << n) - 1] << endl;
        return 0;
    }

     

  • SDOI2018 旧试题

    $$ \sum_{1\le i\le A}{\sum_{1\le j\le B}{\sum_{1\le k\le C}{\sum_{x|i}{\sum_{y|j}{\sum_{z|k}{\left[ gcd\left( x,y \right) ==1 \right] \left[ gcd\left( x,z \right) ==1 \right] \left[ gcd\left( y,z \right) ==1 \right]}}}}}} \\ \sum_{1\le i\le A}{\sum_{1\le j\le B}{\sum_{1\le k\le C}{\sum_{x|i}{\sum_{y|j}{\sum_{z|k}{\left[ gcd\left( x,y \right) ==1 \right] \left[ gcd\left( x,z \right) ==1 \right] \left[ gcd\left( y,z \right) ==1 \right]}}}}}} \\ \sum_{1\le x\le A}{\sum_{1\le i\le \lfloor \frac{A}{x} \rfloor}{\sum_{1\le y\le B}{\sum_{1\le j\le \lfloor \frac{B}{y} \rfloor}{\sum_{1\le z\le C}{\sum_{1\le k\le \lfloor \frac{C}{z} \rfloor}{\left[ gcd\left( x,y \right) ==1 \right] \left[ gcd\left( x,z \right) ==1 \right] \left[ gcd\left( y,z \right) ==1 \right]}}}}}} \\ \sum_{1\le x\le A}{\sum_{1\le y\le B}{\sum_{1\le z\le C}{\lfloor \frac{A}{x} \rfloor \lfloor \frac{B}{y} \rfloor \lfloor \frac{C}{z} \rfloor \sum_{u|x\ and\ u|y}{\mu \left( u \right)}\sum_{v|x\ and\ v|z}{\mu \left( v \right)}\sum_{w|y\ and\ w|z}{\mu \left( w \right)}}}} \\ \sum_{1\le u\le \min \left( A,B \right)}{\sum_{1\le v\le \min \left( A,C \right)}{\sum_{1\le w\le \min \left( B,C \right)}{\mu \left( u \right) \mu \left( v \right) \mu \left( w \right)}}}\sum_{u|x\ and\ u|y}{\sum_{v|x\ and\ v|z}{\sum_{w|y\ and\ w|z}{\lfloor \frac{A}{x} \rfloor \lfloor \frac{B}{y} \rfloor \lfloor \frac{C}{z} \rfloor}}} \\ \sum_{1\le u\le \min \left( A,B \right)}{\sum_{1\le v\le \min \left( A,C \right)}{\sum_{1\le w\le \min \left( B,C \right)}{\mu \left( u \right) \mu \left( v \right) \mu \left( w \right)}}}\sum_{lcm\left( u,v \right) |x}{\lfloor \frac{A}{x} \rfloor \sum_{lcm\left( u,w \right) |y}{\lfloor \frac{B}{y} \rfloor \sum_{lcm\left( w,v \right) |z}{\lfloor \frac{C}{z} \rfloor}}} \\ \text{设}f\left( p,A \right) =\sum_{p|x\ and\ x\le A}{\lfloor \frac{A}{x} \rfloor} \\ \sum_{1\le u\le \min \left( A,B \right)}{\sum_{1\le v\le \min \left( A,C \right)}{\sum_{1\le w\le \min \left( B,C \right)}{\mu \left( u \right) \mu \left( v \right) \mu \left( w \right) f\left( lcm\left( u,v \right) ,A \right) f\left( lcm\left( u,w \right) ,B \right) f\left( lcm\left( w,v \right) ,C \right)}}} \\ \text{可以注意到不为0的}\mu \left( x \right) \text{的个数不多。} \\ \text{可以构建一张图,图中的点是满足}\mu \left( x \right) \text{不为0的}x\text{,两个点}u,v\text{之间有边当且仅当}\mu \left( u \right) \ne \text{0且}\mu \left( v \right) \ne \text{0且}lcm\left( u,v \right) <\max \left( A,B,C \right) \\ \text{可以断定满足}lcm\left( u,v \right) <10^5\text{的}u,v\text{并不多}. \\ \text{所以直接枚举}lcm\left( u,v \right) \text{建图。} \\ \text{如果要满足}\mu \left( u \right) \ne \text{0且}\mu \left( v \right) \ne \text{0,那么一定满足}\mu \left( uv \right) \ne 0. \\ \text{所以枚举所有}\mu \left( x \right) \ne \text{0且}x\le \max \left( A,B,C \right) \text{的}x,\text{枚举}x\text{的质因子集合}S\text{的一个子集}u\text{,然后再枚举}u\text{的一个子集}v \\ \text{这样}lcm\left( v\times \frac{x}{u},u \right) =x\text{显然成立}. \\ \text{设}S=2\times 3\times 5\times 7 \\ u=2\times 5 \\ \text{则如果一个}v\text{满足}lcm\left( u,v \right) =S,\text{那么}v\text{中一定包含质因子5,7,同时可以包含}u\text{的任何一个子集。} \\ \text{建图之后,去掉所有重边和自环。} \\ \text{然后考虑如何枚举三元环。} \\ \text{直接暴力枚举显然是有问题的。} \\ \text{首先把所有无向边重定向为有向边,对于边}\left( u,v \right) ,\text{如果}deg\left( u \right) <deg\left( v \right) ,\text{则让}u\text{指向}v,\text{如果}deg\left( u \right) =deg\left( v \right) , \\ \text{则让编号小的指向编号大的} \\ \text{可以证明,这样每个点的出度不会超过}\sqrt{n} \\ \text{然后直接对于每个点}u\text{,暴力枚举两条出边}\left( u,v \right) \ \left( u,w \right) ,\text{然后看是否满足}lcm\left( v,w \right) \le \max\text{,如果满足,则说明存在无序三元环} \\ \left( u,v,w \right) ,\text{统计进答案。} \\ \text{这只考虑了三元环三个数均不相同的情况,除此之外还需要考虑两个数相同和三个数都相同的情况。} \\ \\ \\ \\ \\ \ $$

    #pragma GCC optimize("O3")
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    #include <assert.h>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 1e9 + 7;
    
    const int_t LARGE = 1e5;
    
    char mu[LARGE + 1];
    int_t factor[LARGE + 1];
    std::vector<int_t> pfactor[LARGE + 1];
    int f[4][LARGE + 1];
    
    int gcd(int a, int b)
    {
        if (b == 0)
            return a;
        else
            return gcd(b, a % b);
    }
    int lcm(int a, int b)
    {
        return a / gcd(a, b) * b;
    }
    void calc_f(int_t id, int_t A)
    {
        for (int_t i = 1; i <= A; i++)
        {
            for (int_t j = 1; j * i <= A; j++)
            {
                f[id][i] = (f[id][i] + A / (j * i)) % mod;
            }
        }
    }
    int prod(int set, int n)
    {
        int prod = 1;
        for (size_t i = 0; i < pfactor[n].size(); i++)
        {
            if (set & (1 << i))
                prod *= pfactor[n][i];
        }
        return prod;
    }
    int_t process(int_t A, int_t B, int_t C)
    {
        struct Pair
        {
            int v1, v2;
        };
        static std::vector<int> graph[LARGE + 1];
        static int degree[LARGE + 1];
        std::vector<Pair> edges;
        memset(f, 0, sizeof(f));
        calc_f(1, A);
        calc_f(2, B);
        calc_f(3, C);
        int max = std::max({A, B, C});
        for (int i = 1; i <= max; i++)
        {
            graph[i].clear();
            degree[i] = 0;
        }
        for (int i = 1; i <= max; i++)
        {
            for (int j = 0; j < (1 << pfactor[i].size()); j++)
            {
                int set = j;
                int c = ((1 << pfactor[i].size()) - 1) & (~set);
                for (int k = 0; k <= j; k++)
                {
                    if ((k & j) == k)
                    {
                        int v1 = prod(j, i), v2 = prod(k | c, i);
                        edges.push_back({v1, v2});
                        degree[v1] += 1;
                        degree[v2] += 1;
                    }
                }
            }
        }
        for (const auto &edge : edges)
        {
            if (degree[edge.v1] < degree[edge.v2] || (degree[edge.v1] == degree[edge.v2] && edge.v1 < edge.v2))
            {
                graph[edge.v1].push_back(edge.v2);
            }
        }
    
        int_t result = 0;
        ///三个点互异的三元环
        const auto f1 = [&](int a, int b, int c) -> int_t {
            int_t res = 0;
            int p = mu[a] * mu[b] * mu[c];
            int ab = lcm(a, b);
            int bc = lcm(b, c);
            int ca = lcm(c, a);
            //(ab)(bc)(ca)
            res = (res + 1ll * ::f[1][ab] * ::f[2][bc] * ::f[3][ca]) % mod;
            //(ab)(ca)(bc)
            res = (res + 1ll * ::f[1][ab] * ::f[2][ca] * ::f[3][bc]) % mod;
            //(bc)(ab)(ca)
            res = (res + 1ll * ::f[1][bc] * ::f[2][ab] * ::f[3][ca]) % mod;
            //(bc)(ca)(ab)
            res = (res + 1ll * ::f[1][bc] * ::f[2][ca] * ::f[3][ab]) % mod;
            //(ca)(ab)(bc)
            res = (res + 1ll * ::f[1][ca] * ::f[2][ab] * ::f[3][bc]) % mod;
            //(ca)(bc)(ab)
            res = (res + 1ll * ::f[1][ca] * ::f[2][bc] * ::f[3][ab]) % mod;
            return (res * p % mod + mod) % mod;
        };
        for (int i = 1; i <= max; i++)
        {
            auto &curr = graph[i];
            for (int j = 0; j < curr.size(); j++)
            {
                for (int k = j + 1; k < curr.size(); k++)
                {
                    if (lcm(curr[j], curr[k]) <= max)
                        result = (result + f1(i, curr[j], curr[k])) % mod;
                }
            }
        }
        //有两个点相同的三元环
        const auto f2 = [&](int a, int b) -> int_t {
            // return 0;
            int_t res = 0;
            int p1 = mu[a] * mu[a] * mu[b];
            int p2 = mu[a] * mu[b] * mu[b];
            int ab = lcm(a, b);
            //(ba) (aa) (ab)
            res = (res + 1ll * p1 * ::f[1][ab] * ::f[2][a] * ::f[3][ab]) % mod;
            //(ab) (ba) (aa)
            res = (res + 1ll * p1 * ::f[1][ab] * ::f[2][ab] * ::f[3][a]) % mod;
            //(aa) (ab) (ba)
            res = (res + 1ll * p1 * ::f[1][a] * ::f[2][ab] * ::f[3][ab]) % mod;
            //(bb) (ba) (ab)
            res = (res + 1ll * p2 * ::f[1][b] * ::f[2][ab] * ::f[3][ab]) % mod;
            //(ba) (ab) (bb)
            res = (res + 1ll * p2 * ::f[1][ab] * ::f[2][ab] * ::f[3][b]) % mod;
            //(ab) (bb) (ba)
            res = (res + 1ll * p2 * ::f[1][ab] * ::f[2][b] * ::f[3][ab]) % mod;
            return (res % mod + mod) % mod;
        };
        for (int i = 1; i <= max; i++)
        {
            auto &curr = graph[i];
            for (int j = 0; j < curr.size(); j++)
            {
                result = (result + f2(i, curr[j])) % mod;
            }
        }
        //三个点都相同的三元环
        const auto f3 = [&](int x) -> int_t {
            return (1ll * mu[x] * mu[x] * mu[x] * f[1][x] * f[2][x] % mod * f[3][x] % mod + mod) % mod;
        };
        for (int_t i = 1; i <= max; i++)
        {
            if (mu[i] != 0)
                result = (result + f3(i)) % mod;
        }
        return result;
    }
    void init()
    {
    
        for (int_t i = 1; i <= LARGE; i++)
        {
            factor[i] = i;
        }
        for (int_t i = 2; i <= LARGE; i++)
        {
            if (factor[i] == i)
            {
                for (int_t j = i * i; j <= LARGE; j += i)
                {
                    factor[j] = i;
                }
            }
        }
        mu[1] = 1;
        for (int_t i = 2; i <= LARGE; i++)
        {
            int_t fact = factor[i];
            if (i / fact % fact == 0)
                mu[i] = 0;
            else
                mu[i] = -mu[i / fact];
        }
        for (int_t i = 2; i <= LARGE; i++)
        {
            if (mu[i] == 0)
                continue;
            int_t curr = i;
            while (curr != 1)
            {
                pfactor[i].push_back(factor[curr]);
                curr /= factor[curr];
            }
        }
    }
    int main()
    {
        init();
        int_t T;
        cin >> T;
        for (int_t i = 1; i <= T; i++)
        {
            int_t A, B, C;
            cin >> A >> B >> C;
            cout << process(A, B, C) << endl;
        }
        return 0;
    }