计数(数论,一题多解)


题目

描述
给定n,m,k都是小于10001的正整数,输出给定的n个数中,其m次幂能被k整除的数的个数。输出满足条件的数的个数。
输入
两行组成,第一行是n,m,k。第二行是n个正整数,不超过10001.
输出
输出满足条件的数的个数。
样例输入
3 2 50
9 10 11
样例输出
1

法一(暴力)

暴力快速幂不说了

法二(指数)

指数循环节
a m % k = a m % φ ( k ) + φ ( k ) % k a^m \%k=a^{m\%\varphi(k)+\varphi(k)}\%k am%k=am%φ(k)+φ(k)%k
证明点这里绝对不是我不会证

#include <cstdio>
#include <iostream>
using namespace std;

int n, m, k, ans, u, ph_k;

inline int phi(int x){
    int sum = x;
    for(int i = 2; x != 1; i ++){
        if( x%i == 0 ){
            sum = sum/i*(i-1);
            while( x%i == 0 )
                x /= i;
        }
    }
    return sum;
}

inline int qkp(int x, int y){
    int sum = 1;
    while( y ){
        if( y&1 )
            sum = sum*x%k;
        x = x*x%k;
        y >>= 1;
    }
    return sum;
}

int main(){
    scanf("%d%d%d",&n,&m,&k);
    ph_k = phi(k);
    if( m > ph_k )
        m = m%ph_k+ph_k;
    for(int i = 1; i <= n; i ++){
        scanf("%d", &u);
        u %= k;
        if( !qkp(u, m) )
            ans ++;
    }
    printf("%d\n", ans);
    return 0;
}
法三(分解)

整数的唯一分解
不知道的点这里
我们知道若 a % k = = 0 a\%k ==0 a%k==0
a = p 1 w 1 ∗ p 2 w 2 ∗ … ∗ p o w o a=p_1^{w_1}*p_2^{w_2}*…*p_o^{w_o} a=p1w1p2w2powo
k = p 1 g 1 ∗ p 2 g 2 ∗ … ∗ p q g q k=p_1^{g_1}*p_2^{g_2}*…*p_q^{g_q} k=p1g1p2g2pqgq
那么一定有 q &lt; = o , a 的 p i = k 的 p i ( i &lt; = q ) 且 ( a 的 p i 的 w i ) 一 定 &gt; ( k 的 p i 的 g i ) q&lt;=o,a的p_i=k的p_i(i&lt;=q)且(a的p_i的w_i)一定&gt;(k的p_i的g_i) q<=oapi=kpi(i<=q)(apiwi)>(kpigi)
所以我们先把 a a a分解之后,再用上面的定理判断 a b 和 k a^b和k abk即可

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n, m, k, ans, u, cnt;

int p[14], w[14], wu[14];

inline int fen(int x){
    memset(wu, 0, sizeof(wu));
    for(int i = 1; i <= cnt; i ++){
        while( x%p[i] == 0 ){
            wu[i]++;
            x/=p[i];
        }
        wu[i] *= m;
        if( wu[i] < w[i] )
            return 1;
    }
    return 0;
}

int main(){
    scanf("%d%d%d",&n,&m,&k);
    int x = k;
    for(int i = 2; i <= k; i ++){
        if( x%i == 0 ){
            p[++cnt] = i;
            while( x%i == 0 ){
                x /= i;
                w[cnt]++;
            }
        }
    }
    for(int i = 1; i <= n; i ++){
        scanf("%d", &u);
        if( fen(u) == 0 )
            ans ++;
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值