AcWing Round #21

A. 整数幂

题目链接


给定两个整数 k k k 和 l l l,请判断是否存在一个正整数 n n n,满足 k n = l kn=l kn=l。

输入格式

第一行包含整数 T T T,表示共有 T T T 组测试数据。

每组数据占两行,第一行包含整数 k k k,第二行包含整数 l l l。

输出格式

每组数据输出一行结果,如果存在 n n n,则输出 YES,否则输出 NO

数据范围

前三个测试点满足, 2 ≤ k , l ≤ 100 2\leq k,l\leq 100 2≤k,l≤100。
所有测试点满足, 1 ≤ T ≤ 10 1\leq T\leq 10 1≤T≤10, 2 ≤ k , l ≤ 2 31 − 1 2\leq k,l\leq 2^{31}−1 2≤k,l≤231−1。

输入样例:

2
5
25
3
8

输出样例:

YES
NO

题目分析:

手速题,暴力枚举。

Code

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

LL get_c(int a, int k)
{
    LL res = 1;
    for (int i = 0; i < k; i ++ )
        res *= a;
    return res;
}

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        int k, l;
        cin >> k >> l;
        bool flag = false;
        for (int i = 0; i <= 50; i ++ )
            if (get_c(k, i) == l) 
            {
                flag = true;
                break;
            }
        if (flag) puts("YES");
        else puts("NO");
    }
    return 0;
}

B. 变成1

题目链接


给定一个二进制数 x x x,在它变为 1 1 1 之前,不断对它进行如下操作:

  • 如果 x x x 为奇数,则将 x x x 加 1 1 1。

  • 如果 x x x 为偶数,则将 x 除以 2 2 2。

请问,多少次操作后, x x x 会变为 1 1 1。

输入格式

共一行,一个 01 字符串,表示二进制数 x x x。

输出格式

一个整数,表示所需操作次数。

数据范围

前六个测试点满足, x x x 的位数不超过 11 11 11。
所有测试点满足, x x x 的首位不为 0 0 0,且位数不超过 1 0 6 10^6 106。

输入样例1:

1

输出样例1:

0

输入样例2:

1001001

输出样例2:

12

输入样例3:

101110

输出样例3:

8

题目分析:

由于 x x x 最多可以是 1 0 6 10^6 106 位,因此需要使用高精度根据题意进行模拟。

但实际上可以不用高精度的方式,转而对二进制数串进行操作,利用双指针的思想处理。

例如对于一个给定的二进制数串 101110,从后往前操作:
AcWing Round #21
手动模拟一下可以发现规律:若当前这一位是 0 0 0 时,直接操作数 + 1,然后右移一位;若当前这一位是 1 1 1,需要加 1 1 1,那就需要找到所有连续的 1 1 1 的个数,因为加上 1 1 1 之后这些连续的 1 1 1 都会由于进位的原因全部变成 0 0 0,那么操作数就等于连续 1 1 1 的个数加上 1 1 1。

这样,我们就可以设置两个指针 i i i 和 j j j,然后累加操作步数即可,具体步骤见代码。

Code

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int main()
{
    string str;
    cin >> str;
    reverse(str.begin(), str.end()); // 将 01 串倒过来操作
    int cnt = 0;
      
    for (int i = 0; i < str.size() - 1; i ++ )
    {
        if (str[i] == '0') ++ cnt; 
        else
        {
            int j = i;
            while (j < str.size() && str[j] == '1') j ++ ;
            cnt += j - i + 1;
            str[j] = '1';
            i = j - 1;
        }
    }
    cout << cnt << endl;
    return 0;
}

C. 最大公约数

题目链接


给定两个正整数 a , m a,m a,m,其中 a < m a<m a<m。

请你计算,有多少个小于 m m m 的非负整数 x x x 满足:

gcd ⁡ ( a , m ) = gcd ⁡ ( a + x , m ) \gcd(a,m) = \gcd(a+x,m) gcd(a,m)=gcd(a+x,m)

输入格式

第一行包含整数 T T T,表示共有 T T T 组测试数据。

每组数据占一行,包含两个整数 a , m a,m a,m。

输出格式

每组数据输出一行结果,一个整数,表示满足条件的非负整数 x x x 的个数。

数据范围

前三个测试点满足, 1 ≤ T ≤ 10 1\leq T\leq 10 1≤T≤10。
所有测试点满足, 1 ≤ T ≤ 50 1\leq T\leq 50 1≤T≤50, 1 ≤ a < m ≤ 1 0 10 1\leq a<m\leq 10^{10} 1≤a<m≤1010。

输入样例:

3
4 9
5 10
42 9999999967

输出样例:

6
1
9999999966

题目分析:

a < m a < m a<m。令 d = gcd ⁡ ( a , m ) = gcd ⁡ ( a + x , m ) d = \gcd(a, m) = \gcd(a + x, m) d=gcd(a,m)=gcd(a+x,m),则 d ∣ a ,   d ∣ m d\mid a,\ d\mid m d∣a, d∣m,而又 ∵ \because ∵ d ∣ a ,   d ∣ m d\mid a,\ d\mid m d∣a, d∣m,且 d ∣ ( a + x ) d\mid (a + x) d∣(a+x), ∴ d ∣ x \therefore d\mid x ∴d∣x。

令 a ′ = a d ,   m ′ = m d ,   x ′ = x d a' = \dfrac{a}{d},\ m' = \dfrac{m}{d},\ x' = \dfrac{x}{d} a′=da​, m′=dm​, x′=dx​,则 gcd ⁡ ( a ′ + x ′ , m ′ ) = 1 \gcd(a' + x', m') = 1 gcd(a′+x′,m′)=1,问题转化为:有多少个满足要求的 x ′ x' x′ 使得 ( a ′ + x ′ ) (a' + x') (a′+x′) 与 m ′ m' m′ 互质。

∵ 0 ≤ x < m \because 0\leq x < m ∵0≤x<m, ∴ 0 ≤ x ′ < m \therefore 0\leq x' < m ∴0≤x′<m,两边同加上 a ′ a' a′,得 a ′ ≤ x ′ < a ′ + m ′ a'\leq x' < a' + m' a′≤x′<a′+m′,即求 [ a ′ ,   a ′ + m ′ ) [a',\ a' + m') [a′, a′+m′) *有多少个数与 m ′ m' m′ 互质。

AcWing Round #21

图中红色的两段 [ 0 , a ′ ) [0, a') [0,a′) 和 [ m ′ , a ′ + m ′ ) [m', a' + m') [m′,a′+m′) 在   m o d     m ′ \bmod\ m' mod m′ 的意义下数值是一样的,那么与之互质的数的情况也就是一样的,故我们求 [ a ′ , a ′ + m ′ ) [a', a' + m') [a′,a′+m′) 中有多少个与 m ′ m' m′ 互质的数,就可以转化为求 [ 0 , m ′ ) [0, m') [0,m′) 中与 m ′ m' m′ 互质的数的个数,求一下 m ′ m' m′ 的欧拉函数 φ ( m ′ ) \varphi (m') φ(m′) 即可。

关于欧拉函数的求解和证明过程,可以参考:AcWing 873. 欧拉函数

注意,本题不可使用 筛法求欧拉函数 进行求解,筛法求欧拉函数时间复杂度是线性的,可以求出 1 ∼ n 1\sim n 1∼n 中每个数的欧拉函数,但本题的部分数据可能达到 1 0 10 10^{10} 1010,线性筛不能够在时限内求出所需要数的欧拉函数

时间复杂度分析:

每组数据只需要求出其欧拉函数即可,复杂度为 n \sqrt n n ​,一共有 50 50 50 组数据,值最大可达 1 0 10 10^{10} 1010,因此总的计算量约为 50 × 1 0 10 ≈ 5 × 1 0 6 50\times \sqrt {10^{10}} \approx 5\times 10^6 50×1010 ​≈5×106。

Code

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

LL gcd(LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

LL phi(LL m)
{
    LL res = m;
    for (int i = 2; i <= m / i; i ++ )
        if (m % i == 0)
        {
            res = res / i * (i - 1);
            while (m % i == 0) m /= i;
        }
    if (m > 1) res = res / m * (m - 1);
    return res;
}

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        LL a, m;
        cin >> a >> m;
        m = m / gcd(a, m);
        cout << phi(m) << endl;
    }
    return 0;
}
上一篇:LeetCode---42. 接雨水 (hard)


下一篇:1.flask源码目录