AcWing杯 - 第 21 场周赛 ( 3997. 整数幂、 3998. 变成1 、3999. 最大公约数)

AcWing 3997. 整数幂

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

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

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

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

数据范围
前三个测试点满足,2≤k,l≤100。
所有测试点满足,1≤T≤10,2≤k,l≤2^31−1。

输入样例:
2
5
25
3
8
输出样例:
YES
NO

题解:暴力枚举

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

using namespace std;
typedef long long LL;

int main()
{
    int k,l;
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &k, &l);
        LL tmp = k;
        while(tmp<l){
            tmp = tmp * k;
        }
        if(tmp == l){
            printf("YES\n");
        }
        else printf("NO\n");
    }
    return 0;
}

3998. 变成1

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

如果 x 为奇数,则将 x 加 1。
如果 x 为偶数,则将 x 除以 2。
请问,多少次操作后,x 会变为 1。

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

输出格式
一个整数,表示所需操作次数。

数据范围
前六个测试点满足,x 的位数不超过 1。
所有测试点满足,x 的首位不为 0,且位数不超过 10^6。
输入样例1:
1
输出样例1:
0
输入样例2:
1001001
输出样例2:
12
输入样例3:
101110
输出样例3:
8

题解:模拟 + 高精度加法

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

using namespace std;

int main()
{
    string s;
    cin >> s;
    vector<int> q;
    //把字符串倒过来,方便进位往数组后边加1
    for(int i=s.size()-1; i>=0; --i){
        q.push_back(s[i]-'0');
    }
    int k = 0;
    int n = q.size();
    int res = 0;
    //模拟
    while(k < n-1){
    	
        if(q[k] % 2){ //如果末尾为1
        	//t为进位
            int t = 1;
            for(int i=k; i<n; ++i){
                t += q[i];
                q[i] = t % 2;
                t /= 2;
                //当进位为0时就停止
                if(!t) break;
            }
            if(t) q[n++] = 1;
            res++;
        }
        //为0就继续遍历
        k++;
        res++;
    }
    cout<<res<<endl;
    return 0;
}

AcWing 3999. 最大公约数
给定两个正整数 a,m,其中 a<m。

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

gcd(a,m)=gcd(a+x,m)
输入格式
第一行包含整数 T,表示共有 T 组测试数据。

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

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

数据范围
前三个测试点满足,1≤T≤10。
所有测试点满足,1≤T≤50,1≤a<m≤10^10。

输入样例:
3
4 9
5 10
42 9999999967
输出样例:
6
1
9999999966

题解:数学推导+欧拉函数
设gcd(a,m) = gcd(a+x,m) = d
因为 d|a , d|(a+x) ,d|m ( |是整除符号)
所以 d|x
g c d ( a + x , m ) = d gcd(a+x,m) = d gcd(a+x,m)=d中数全部除以其最大公约数 d 得 g c d ( a ′ + x ′ , m ′ ) = 1 gcd(a'+x',m') = 1 gcd(a+x,m)=1
所以求出 a’ + x’ 的区间内和 m’ 互质的个数就是x的个数
因为条件 a < m, x < m
所以 a ′ < m , x ′ < m a'<m, x'<m a<m,x<m
a ′ + x ′ > = m ′ a'+x'>=m' a+x>=m, x ′ x' x 最大是m-1,最小是0,则 a ′ < = a ′ + x ′ < = a ′ + m ′ − 1 a'<=a'+x'<=a'+m'-1 a<=a+x<=a+m1
a ′ + x ′ < m ′ a'+x'<m' a+x<m, x ′ x' x 最大是m-1,最小是0,则 a ′ < = a ′ + x ′ < = m ′ − 1 ′ a'<=a'+x' <=m'-1' a<=a+x<=m1
两者取并集,则区间为 [ a ′ , a ′ + m ′ − 1 ] [a',a'+m'-1] [a,a+m1],就是求在这个区间内和 m ′ m' m互质的个数不好求
因为 [ 0 , a ′ ) [0,a' ) [0,a) 区间内与 [ m ′ , a + m ′ ) [m', a+m') [m,a+m) m ′ m' m 互质个数相同,因为余数一样,所以区间替换一下
左闭右开是因为原本区间右侧就到 a+m’-1, 替换后的区间为 [ 0 , m ′ ) [0,m') [0,m)
求这个区间内和m’ 互质的个数就是求欧拉函数,得解

#include<iostream>
#include<cstring>
#include <cmath>
using namespace std;
typedef long long LL;

LL mygcd(LL a, LL b)
{
    if(b==0) return a;
    else return mygcd(b,a%b);
}


LL phi(LL n)
{
    // 欧拉函数
    LL res = n;
    for(int i=2; i<=n/i; ++i){
        if(n%i==0){
            res = res /i *(i-1); 
            while(n%i==0){
                n/=i;
            }
        }
    }
    if(n>1){
        res = res /n * (n-1);
    }
    return res;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        LL a,m;
        scanf("%lld%lld", &a, &m);
        LL d = mygcd(a,m);
        m/=d;
        cout << phi(m) << endl;
        
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葛济维的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值