• 算法基础-数学知识-容斥原理、博弈论


    容斥原理

    在这里插入图片描述
    容斥原理可以画一个韦恩图来看各个集合的关系

    890. 能被整除的数(二进制状态压缩版本,复杂度多一个Om)

    #include 
    #include 
    #include 
    
    using namespace std;
    typedef long long LL;
    const int N = 17;
    int p[N];
    void solve()
    {
        int n, m;
        cin >> n >> m;
        for (int i = 0; i < m; ++ i) cin >> p[i];
    
        int res = 0;
        for (int i = 1; i < 1 << m; ++ i)//枚举2的n次方-1个集合
        {
            int t = 1, cnt = 0;
            for (int j = 0; j < m; ++ j)//判断是否乘上p[j]
            {
                if (i >> j & 1)
                {
                    if ((LL)t * p[j] > n)
                    {
                        t = -1;
                        break;
                    }
                    t *= p[j];
                    cnt ++ ;
                }
            }
            if (t != -1)
            {
                if (cnt & 1) res += n / t;//奇数就加上,偶数就减去
                else res -= n / t;
            }
        }
    
        cout << res;
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    890. 能被整除的数(dfs版本)

    本题本质上就是一个枚举所有答案的过程,那么我们当然可以用dfs搜索到所有可能的方案

    #include 
    #include 
    #include 
    
    using namespace std;
    typedef long long LL;
    const int N = 17;
    int p[N];
    int n, m;
    int res = 0;
    void dfs(int u, int t, bool add)
    {
        if (u == m)
        {
            if (t == 1) return ;
            else 
            {
                if (add) res += n / t;
                else res -= n / t;
                return;
            } 
        }
        dfs(u + 1, t, add);//m个质数中不选择p[i]
        if ((LL)t * p[u] <= n)//m个质数中不选择p[i]
        {
            dfs(u + 1, t * p[u], !add);//本层选了一个数的话,下一层枚举的集合的add就要取反,因为容斥原理公式就是1个的+,2个的-,3个的+,每多选一个数字,加减号相反
        }
    }
    void solve()
    {
        cin >> n >> m;
        for (int i = 0; i < m; ++ i) cin >> p[i];
    
        dfs(0, 1, false);
        cout << res;
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    博弈论

    在这里插入图片描述

    1. 为什么异或值=0先手必败?这个我没搞懂,我主要是记住这个结论
    2. 为什么异或值!=0先手必胜?
      因为它可以转化为对手先手必败的状态(异或值为0),推导如下
      在这里插入图片描述

    无限制nim游戏

    AcWing 891. Nim游戏

    #include 
    #include 
    #include 
    
    using namespace std;
    const int N = 1e5 + 10;
    int a[N];
    void solve()
    {
       int n;
       cin >> n;
       for (int i = 0; i < n; ++ i) cin >> a[i];
       int t = 0;//异或运算里面的0相当于加法里面的0,乘法里面的1
       for (int i = 0; i < n; ++ i) 
       {
            t ^= a[i];
       }
       if (t) cout << "Yes" << endl;
       else cout << "No" << endl;
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    AcWing 892. 台阶-Nim游戏(待补)

    集合版本Nim游戏

    AcWing 893. 集合-Nim游戏

    1. 集合版本Nim游戏的每一步有多种选择,但多种选择是被限制在一个选择集合中的(而不是随意拿多少个)。
    2. sg(起点) != 0说明 我经过若干步一定可以到达 sg = 0的点,即我还是可以操作的,如果sg(起点) = 0,那我没有任何操作空间,直接判负,即先手必败。
    3. 推荐看这个博客
      在这里插入图片描述
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    const int N = 1e4 + 10;
    int s[N], f[N];//f可以不用,但可以起到剪枝的效果
    int n, k;
    
    int sg(int x)
    {
        if (f[x] != -1) return f[x];
        
        set<int> S;
        for (int i = 0; i < k; ++ i)
            if(x >= s[i]) S.insert(sg(x - s[i]));//这里如果不判断x>=s[i]的话会影响后续路线的赋值,
                                            //本来下一层应该是1,2但是因为负数,变成了0, 1
                                            //那么本层本来是0的,递归回来的时候现在也会被影响变成了2
        
        for (int i = 0; i < k; ++ i)
        {
            if (S.count(i) == 0) return f[x] = i;
        }
    }
    
    void solve()
    {
        memset(f, -1, sizeof f);
        cin >> k;
        for (int i = 0; i < k; ++ i) cin >> s[i];
        
        cin >> n;
    
        int x;
        int res = 0;
        while(n --)
        {
            cin >> x;
            res ^= sg(x);
        }
    
        if (res) cout << "Yes" << endl;
        else cout << "No" << endl; 
    
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    AcWing 894. 拆分-Nim游戏(待补)

    • 相关阅读:
      Typora图片上传阿里云对象存储OSS
      NL2SQL进阶系列(1):DB-GPT-Hub、SQLcoder、Text2SQL开源应用实践详解
      AtCoder Beginner Contest 260 G.Scalene Triangle Area(花式二维差分/二维线段树)
      SparkSQL的Join的实现方式
      HC32单片机的TIMERA输出波形极性不对的问题
      [附源码]计算机毕业设计JAVA疫情防控下高校教职工健康信息管理系统
      Vue3:父组件向子组件传值(Props)
      Scientific Reports|比较转录组分析揭示了杀菌剂氰烯菌酯对尖孢镰刀菌的抗性调控机制和杀菌活性
      ubuntu为可执行程序添加桌面图标
      【一起学Rust | 框架篇 | iced框架】rust原生跨平台GUI框架——iced
    • 原文地址:https://blog.csdn.net/chirou_/article/details/132722772