• codeforces 900D 数论+组合+容斥原理


    问有多少个这样的数字序列

    所有数的GCD等于x 并且 所有数的和等于y

    题解:

    非常难有思路啊 看题解后过的。

    考虑序列GCD为x的倍数 即GCD = n*x 和当然都为y 这个条件不要忘了

    这样我们可以用  容斥原理来递推的计算GCD为n*x的序列个数是多少

    怎么计算呢

    以样例为例子 3 9

    当GCD = 3 的时候 可以有9 / 3 = 3 个3 序列是这样的 3 3 3

    那么有三个空 用插板法 可以计算可以插板的方式数位2**(3-1) = 2**2 = 4种

    这里解释插板的意义 3|3 3插一个板就表示相邻的数求和 那么3|3 3 就是 6 3

    同理 3 3|3 -> 3 6; 3|3|3 -> 9; 但是这样插板出现了问题 就是出现了GCD 并不为3的序列 即 9

    这个时候就需要用容斥原理来 递推 

    设a[i] 表示GCD为i的序列个数, a[j] 表示GCD为j个数

    不妨设i > j

    if (i % j == 0) a[j] = (a[j]+MOD-a[i]) % MOD; 因为 GCD 为i的情况是一定可以通过插板 得到GCD 为j的情况

    而通过从大到小的递推 a[i]已经是容斥后的结果 

    这样最终得到GCD最小为x 的结果就是答案 网上题解写的有点不太清楚 这里自己补充点自己的理解。轻喷。。

    代码君:

     1 #include <bits/stdc++.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <stdio.h>
     5 #define pb push_back
     6 
     7 const int MOD = 1e9+7;
     8 const int MAXN = 1e5+7;
     9 typedef long long ll;
    10 
    11 using namespace std;
    12 
    13 ll x, y;
    14 
    15 ll mypow(ll base, ll p)
    16 {
    17     if (p == 0) return 1;
    18     ll tmp = mypow(base, p/2);
    19     if (p & 1) tmp = (tmp*tmp*base) % MOD;
    20     else tmp = (tmp*tmp) % MOD;
    21     return tmp;
    22 }
    23 vector<ll> a;
    24 ll dp[MAXN];
    25 int main()
    26 {
    27     //freopen("in.txt", "r", stdin);
    28     while (cin >> x >> y)
    29     {
    30         a.clear();
    31         if (y % x != 0)
    32         {
    33             cout << 0 << endl;
    34             continue;
    35         }
    36         for (ll i = 1; i*i <= y; i++)
    37         {
    38             if (i % x == 0 && y % i == 0) a.pb(i);
    39             if (i*i != y && y % i == 0 && (y/i)%x==0 ) a.pb(y/i);
    40         }
    41         sort(a.begin(), a.end());
    42         for (int i = 0; i < a.size(); i++) dp[i] = mypow(2, (y/a[i]-1));
    43         for (int i = (int)a.size()-1; i >= 0; i--)
    44             for (int j = i+1; j < a.size(); j++) 
    45                 if (a[j] % a[i] == 0) 
    46                 {
    47                     dp[i] -= dp[j];
    48                     dp[i] = (dp[i] + MOD) % MOD;
    49                 }
    50         cout << dp[0] << endl;
    51     }
    52     return 0;
    53 }    
    View Code
  • 相关阅读:
    orleans 的一种模式
    在.net4的环境下使用Microsoft.AspNet.SignalR.Client 2.4.0
    微信卡券领用的附加测试
    SVN忽略本地文件不提交,同时不删除服务器上的文件
    SQL Server 2017安装错误:Polybase要求安装Oracle JRE 7更新51或更高版本的两种解决方法
    SQL Server遍历表(临时表)
    无法确定条件表达式的类型,因为“DateTime”和“<null>”之间没有隐式转换|Nullable类型问题与?:条件运算符
    C# 反射获取对象的内容
    c# 计算执行时间,性能,运行时间Stopwatch
    JS,JQuery循环数组,循环对象生成需要的数据
  • 原文地址:https://www.cnblogs.com/oscar-cnblogs/p/8516494.html
Copyright © 2020-2023  润新知