zoukankan      html  css  js  c++  java
  • 【题解】玲珑杯河南专场17B

      容斥大法妙~其实网上很多的题解虽然给出了容斥系数,但是并没有说明为什么是这个样子的。在这里解释一下好了。

      考虑用容斥,实际上就是让 (ans = sum_{Tsubseteq S}^{ }f_{T}*h_{T})。其中,(f) 为容斥的系数,而 (h) 为一个集合的‘贡献’。这个贡献的值往往对于集合当中的各个元素而言是独立的。由于这题中是要我们求出所有的被操作了奇数次的灯的数量,所以有:

    (g_{x}=sum_{i = 1}^{x}inom{x}{i}*f_{i}=[x&1])

    (g_{x}) 为是原数列中 (x) 个数的倍数的数所对答案产生的贡献

    令(f[0] = 0),

    则(g_{x}=sum_{i = 0}^{x}inom{x}{i}*f_{i}=[x&1])

    那么根据二项式反演,有

    (f_x = sum_{i = 0}^{x} g_i * inom{x}{i}*(-1)^{x - i})

    (f_x = sum_{i = 0}^{x}inom{x}{i}*(-1)^{x - i}[i&1])

    根据(f_x = sum_{i = 0}^{x}inom{x}{i}*(-1)^{x - i}[i&1])

    对(x) 的奇偶性分类讨论一下,再加上:

    (inom{n}{1}+inom{n}{3}+inom{n}{5}...=2^{n - 1})

    (这个式子就不用解释了吧……)

    然后就得到了(f_x) 的表达式~

      下面这份代码为 (n^{2}) 求出容斥系数,但实际上可以按照上文所说做到(O(1))……

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1000
    #define int long long
    int n, m, ans, cnt, S[maxn];
    int f[maxn], a[maxn], C[maxn][maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void Pre()
    {
        for(int i = 0; i < 30; i ++) C[i][0] = 1;
        for(int i = 1; i < 30; i ++)
            for(int j = 1; j < 30; j ++)
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
    }
    
    int Get(int x)
    {
        int t = x & 1;
        for(int i = 1; i < x; i ++)
            t -= C[x][i] * f[i];
        return t;
    }
    
    int gcd(int a, int b)
    {
        int c = 0;
        while(b) c = a % b, a = b, b = c;
        return a;
    }
    
    void dfs(int now)
    {
        if(now == m + 1)
        {
            int lcm = 1;
            for(int i = 1; i <= cnt; i ++)
                lcm = lcm * S[i] / gcd(lcm, S[i]);
            ans += f[cnt] * (n / lcm);
            return;
        }
        S[++ cnt] = a[now]; dfs(now + 1);
        cnt --; dfs(now + 1);
    }
    
    signed main()
    {
        int T = read(); f[0] = 0; f[1] = 1; Pre();
        for(int i = 2; i <= 20; i ++) f[i] = Get(i);
        for(int i = 1; i <= T; i ++)
        {
            n = read(), m = read(); ans = 0;
            for(int j = 1; j <= m; j ++) a[j] = read();
            dfs(1);
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    2-10 案例4:像素读取写入
    2-8 案例3:不同图片质量保存
    2-7 案例2:图片写入
    Linux文件操作实用笔记
    Linux文件操作实用笔记
    Linux 文件系统基础
    Linux 文件系统基础
    一篇故事讲述了计算机网络里的基本概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等...
    一篇故事讲述了计算机网络里的基本概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等...
    30 个与程序猿有关的成语
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/10161876.html
Copyright © 2011-2022 走看看