Wannafly 模拟赛5 E 思维+数论

题目链接


参考博客(感谢)

用自己的语言简单总结一下…加深理解。

题意:
Aria正面临算设课程的考试。

F ( n ) = ∏ i = 1 n ∏ j = 1 i j = ∏ i = 1 n i ! F(n) = \prod_{i=1}^n\prod_{j=1}^{i}j = \prod_{i=1}^ni! F(n)=i=1nj=1ij=i=1ni!
对于给定的n,m(其中n为质数),求F( n m n^m nm)中质因子n的出现次数,即求一个最大的非负整数e满足 n e n^e ne整除F( n m n^m nm)。
由于是算设课的考试,答案当然是对 1 0 9 + 7 10^9+7 109+7取模的。

思路:
首先此题需要基于一个重要的数论知识点:
对于一个数 n n n,所包含的某个因子 m m m的次数是:

int calc(int n,int m){
    int ans = 0;
    while(n){
        ans += n/m;
        n = n/m;
    }
    return ans;
}

证明:
k = n / m k = n/m k=n/m
因为:
n ! = 1 ∗ 2 ∗ 3 ∗ . . . n n! = 1*2*3*...n n!=123...n
试着将因子m提出,则一定有:(C为一个不含因子m的数)
n ! = ( m ∗ ( 2 ∗ m ) ∗ ( 3 ∗ m ) . . . ( k ∗ m ) ) ∗ C n! = (m*(2*m)*(3*m)...(k*m)) * C n!=(m(2m)(3m)...(km))C
     = k ! ∗ m k ∗ C \ \ \ \ = k! * m^k * C     =k!mkC

所以 k k k一定是最后所求个数的一部分。
另一部分则是 k ! k! k!中所包含因子 m m m的个数。递归处理即可。
证毕。


c a l c ( n , m ) calc(n,m) calc(n,m) n ! n! n!中所含因子 m m m的个数。
因为 n n n为质数,则只需要单独考虑 1 − n m 1-n^m 1nm中每个数所含因子 n n n个数的和。

a n s = ∑ i = 1 n m c a l c ( i , n ) ans = \sum_{i=1}^{n^m}calc(i,n) ans=i=1nmcalc(i,n)

由上面的证明的数论知识,我们易得:
对于 i ∈ [ k n , k n + n − 1 ] i \in [kn,kn+n-1] i[kn,kn+n1] c a l c ( i , n ) calc(i,n) calc(i,n)相同
故我们考虑将 1 − n m 1-n^m 1nm中的所有数每 n n n个分为一组,则一组中所有数对答案的贡献相同。
对于 n m n^m nm则需要特殊考虑,故答案可以化简为:

a n s = c a l c ( n m , n ) + ∑ i = 1 n m − 1 c a l c ( i , n ) ans = calc(n^m,n) + \sum_{i=1}^{n^m-1}calc(i,n) ans=calc(nm,n)+i=1nm1calc(i,n)
= ∑ i = 0 m − 1 n i + n ∗ ∑ i = 1 n m − 1 − 1 c a l c ( i ∗ n , n ) = \sum_{i=0}^{m-1}n^i + n*\sum_{i=1}^{n^{m-1}-1}calc(i*n,n) =i=0m1ni+ni=1nm11calc(in,n)

因为: c a l c ( i ∗ n , n ) = i + c a l c ( i , n ) calc(i*n,n) = i + calc(i,n) calc(in,n)=i+calc(i,n)
所以:
a n s = n m − 1 n − 1 + n ∗ ( ∑ i = 1 n m − 1 − 1 i + ∑ i = 1 n m − 1 − 1 c a l c ( i , n ) ) ans = \frac{n^m-1}{n-1} + n*(\sum_{i=1}^{n^{m-1}-1} i + \sum_{i=1}^{n^{m-1}-1}calc(i,n) ) ans=n1nm1+n(i=1nm11i+i=1nm11calc(i,n))

对于括号里面的第二项,可以视为一个子问题递归处理,即得:
a n s = n m − 1 n − 1 + 1 2 ∗ ( n m ( n m − 1 − 1 ) + n m ( n m − 2 − 1 ) + . . . + n m ( n − 1 ) ) ans = \frac{n^m-1}{n-1} + \frac{1}{2}*(n^m(n^{m-1}-1) + n^m(n^{m-2}-1) + ... +n^m(n-1)) ans=n1nm1+21(nm(nm11)+nm(nm21)+...+nm(n1))
= n m − 1 n − 1 + 1 2 ∗ n m ∗ ∑ i = 1 m − 1 ( n i − 1 ) = \frac{n^m-1}{n-1} + \frac{1}{2}*n^m*\sum_{i=1}^{m-1}(n^i-1) =n1nm1+21nmi=1m1(ni1)
= n m − 1 n − 1 + n m 2 ( n m − 1 n − 1 − m ) = \frac{n^m-1}{n-1} + \frac{n^m}{2}(\frac{n^m-1}{n-1} - m) =n1nm1+2nm(n1nm1m)

快速幂+逆元即可。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
 
const ll mod = 1e9 + 7;
 
ll fast_pow(ll n,ll m){
    ll res = 1;
    while(m){
        if(m&1) res = res*n%mod;
        n = n*n%mod;
        m >>= 1;
    }
    return res;
}
 
int main(){
    ll n,m;
    scanf("%lld%lld",&n,&m);
 
    ll res = (fast_pow(n,m)-1)*fast_pow(n-1,mod-2)%mod;
    ll ans = (res + (fast_pow(n,m)*fast_pow(2,mod-2)%mod*(res-m)%mod))%mod;
    if(ans<0) ans += mod;
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值