Codeforces Round #589 (Div. 2) C.Primes and Multiplication (数学推导+容斥原理+快速幂)

写在前面

需要学会的前置技能:
快速幂
一颗热爱学习的心

笔者是一名十八线蒟蒻ACMer ACMerACMer,如果文章有误,请在评论区下留言,我会尽快处理,非常感谢!
注:这个方法并不是最优的,只是笔者在当时想到的一种方法,关于最优方法,各位可以看看出题人自己给出的题解。比较简洁。
再次重申!本文描述的不是最优解!

原题体面

时间限制:1s
空间限制:256 MB
Let’s introduce some definitions that will be needed later.
Let p r i m e ( x ) prime(x) be the set of prime divisors of x x . For example, p r i m e ( 140 ) = ( 2 , 5 , 7 ) prime(140)=(2,5,7) , p r i m e ( 169 ) = ( 13 ) prime(169)=(13) .
Let g ( x , p ) g(x,p) be the maximum possible integer p k p^k where k k is an integer such that x x is divisible by p k p^k . For example:
g ( 45 , 3 ) = 9 g(45,3)=9 ( 45 45 is divisible by 3 2 = 9 3^2=9 but not divisible by 3 3 = 27 3^3=27 ),
g ( 63 , 7 ) = 7 g(63,7)=7 ( 63 63 is divisible by 7 1 = 7 7^1=7 but not divisible by 7 2 = 49 7^2=49 ).
Let f ( x , y ) f(x,y) be the product of g ( y , p ) g(y,p) for all p p in p r i m e ( x ) prime(x) . For example:
f ( 30 , 70 ) = g ( 70 , 2 ) g ( 70 , 3 ) g ( 70 , 5 ) = 2 1 3 0 5 1 = 10 f(30,70)=g(70,2)⋅g(70,3)⋅g(70,5)=2^1⋅3^0⋅5^1=10 ,
f ( 525 , 63 ) = g ( 63 , 3 ) g ( 63 , 5 ) g ( 63 , 7 ) = 3 2 5 0 7 1 = 63 f(525,63)=g(63,3)⋅g(63,5)⋅g(63,7)=3^2⋅5^0⋅7^1=63 .
You have integers x x and n n . Calculate f ( x , 1 ) f ( x , 2 ) f ( x , n ) m o d ( 1 0 9 + 7 ) f(x,1)⋅f(x,2)⋅…⋅f(x,n)mod(10^9+7) .

Input

The only line contains integers x x and n n ( 2 x 1 0 9 , 1 n 1 0 18 2≤x≤10^9, 1≤n≤10^{18} ) — the numbers used in formula.

Output

Print the answer.
Input1

10 2

output1

2

Input2

20190929 1605

output2

363165664

Input3

947 987654321987654321

output3

593574252

Note

In the first example, f ( 10 , 1 ) = g ( 1 , 2 ) g ( 1 , 5 ) = 1 , f ( 10 , 2 ) = g ( 2 , 2 ) g ( 2 , 5 ) = 2 f(10,1)=g(1,2)⋅g(1,5)=1, f(10,2)=g(2,2)⋅g(2,5)=2 .
In the second example, actual value of formula is approximately 1.597 1 0 171 1.597⋅10^{171} . Make sure you print the answer modulo ( 1 0 9 + 7 ) (10^9+7) .
In the third example, be careful about overflow issue.

题面分析

f f 的计算过程又臭又长,直接计算必定超时,所以我们考虑去转化问题。
首先,注意到
f ( x , n ) = i = 1 k g ( n , p i ) f(x,n)=\prod_{i=1}^{k}g(n,p_i) ( k k 为满足 p k < = m p^k<=m 的最大整数)
i = 1 n f ( x , i ) \prod _{i=1}^{n}f(x,i)
= i = 1 k g ( 1 , p i ) i = 1 k g ( 2 , p i ) . . . i = 1 k g ( n , p i ) \prod_{i=1}^{k}g(1,p_i)\prod_{i=1}^{k}g(2,p_i)...\prod_{i=1}^{k}g(n,p_i)
我们枚举去枚举 p i p_i ,可以得到
= i = 1 n g ( i , p 1 ) i = 1 n g ( i , p 2 ) . . . i = 1 n g ( i , p k ) \prod_{i=1}^{n}g(i,p_1)\prod_{i=1}^{n}g(i,p_2)...\prod_{i=1}^{n}g(i,p_k)
然后,根据 g g 的定义注意到
g ( x , p ) p = g ( x p , p ) g(x,p)*p=g(xp,p) ---------①
g ( x , x ) = x g(x,x)=x --------②
结合①②可以得到
g ( x n , x ) = x n g(x^n,x)=x^n ----------③
稍加推导也可以得到
g ( k x n , x ) = x n ( k   m o d   x ! = 0 ) g(kx^n,x)=x^n(k\ mod\ x!=0) ---------④
因此,我们得到一个初步的结论:
对于一个 g ( i , p ) g(i,p) ,我们有
g ( i , p ) = { 1 ( i   m o d   p   0 ) p i = k p ( k   m o d   p   0 ) p 2 i = k p 2 ( k   m o d   p   0 ) . . . p m i = k p m ( k   m o d   p   0 ) g(i,p)= \begin{cases} 1& (i\ mod\ p\ \neq 0)\\ p& i=kp(k\ mod\ p\ \neq0)\\ p^2& i=kp^{2}(k\ mod\ p\ \neq 0)\\ ...\\ p^m& i=kp^m(k\ mod\ p\ \neq 0) \end{cases}
其中 m m 是满足 p m n p^m\leq n 的最大整数

容斥原理

有了上述结论后,我们只要计算出每种答案出现的次数即可。
但可以注意到,当 g ( i , p ) = p g(i,p)=p 时, i i 出现的次数并不是 n / p n/p 这么简单,
因为 n / p n/p 是当 g ( i , p ) 1 g(i,p)\neq 1 的所有情况总和。
因此我们考虑用容斥原理。
先计算 p m p^m ,它作为最大项,没有干扰,因此 p m p^m 出现的次数就是 n / p m \lfloor n/p^m\rfloor
对于 p m 1 p^{m-1} ,它出现的次数并不是是 n / p m 1 \lfloor n/p^{m-1}\rfloor ,而是要去掉之前 p m p^m 的次数 n / p m \lfloor n/p^m\rfloor ,
因此 p m 1 p^{m-1} 出现的次数为 n / p m 1 n / p m \lfloor n/p^{m-1}\rfloor-\lfloor n/p^{m}\rfloor
同理 p m 2 p^{m-2} 出现的次数为 n / p m 2 n / p m 1 n / p m \lfloor n/p^{m-2}\rfloor -\lfloor n/p^{m-1}\rfloor -\lfloor n/p^m\rfloor
同理得到其他的答案出现次数。
a i a_i p i p_i 的出现次数,则
i = 1 n g ( i , p ) = p i = 1 m i a i \prod_{i=1}^{n}g(i,p)=p^{\sum_{i=1}^{m}i*a_i}
有了 g ( i , p ) g(i,p) 之积,答案自然就出来了。
其他的细节请查看代码。总体复杂度未知,初步估计是非常小的。

代码实现(31ms)

//代码很丑,大家将就着看吧......
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5;
/*打一个5e5内的质数表。
因为在数学上可以证明,把n按质因子分解时,至多有一个质因子大于sqrt(n),
因此我们打出sqrt(n)内质数表来分解,剩下分不掉的就是一个质数*/
const long long mod=1e9+7;
bool number[maxn+5];
int prime[maxn+5];
int c=0;//质数总个数
long long x,n;
long long qsm(long long a,long long b,long long c)//快速幂
{
    long long ans=1,base=a;
    while(b!=0)
	{
        if(b&1)
        ans=ans*base%c;
        base=base*base%c;
        b>>=1;
	}
    return ans%c;
}
long long kk(long long a,long long b)//快速乘
{
    long long ans=1,base=a;
    while(b!=0)
	{
        if(b&1)
        ans=ans*base;
        base=base*base;
        b>>=1;
	}
    return ans;
}
long long f(long long p)//计算p的次方数
{
	long long maxp=0,cc=n;//maxp为最大的满足p^m<=n的m
	while(cc>=p)
	{
		maxp++;
		cc/=p;
	}
	long long cs[100];
	cs[maxp]=n/kk(p,maxp);
	long long zx=0;
	for(long long i=maxp-1;i>=1;i--)//倒着算
	{
		zx=(zx+cs[i+1]);//统计之前的次数
		cs[i]=(n/kk(p,i)-zx);//筛去之前有的次数
	}
	long long ans=0;
	for(long long i=1;i<=maxp;i++)
		ans=(ans+(i*cs[i]));//根据各自对答案的贡献计算最后的总次数
	return ans;
	//需要注意的是,这里的总次数应该是小于n本身的,不用担心超出long long 范围,所以可以不用欧拉降幂。
}
void init()//欧线性拉筛
{
    int i,j;
    memset(number,true,sizeof(number));
    memset(prime,-1,sizeof(prime));
    for(i=2;i<=maxn;i++)
    {
        if(number[i])
            prime[c++]=i;
        for(j=0;j<c&&prime[j]*i<=maxn;j++)
        {
            number[prime[j]*i]=false;
            if(i%prime[j]==0) //保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次
                break;
        }
    }
}
int main()
{
	init();
	scanf("%lld%lld",&x,&n);
	long long yz[10000];//x的质因子
	int psum=0;
	for(int i=0;i<c && prime[i]<=x && x>1;i++)//筛因子 
		{
			if(x%prime[i]==0 && && x>1)
			{
				yz[++psum]=prime[i];
				while(x>=prime[i] && x%prime[i]==0)
				{
					x/=prime[i];
				}
			}
		}
	if(x>1)//剩下一个大于sqrt(x)的数,必是质数
	{
		yz[++psum]=x;
	}
	long long ans=1;
	for(int i=1;i<=psum;i++)
	{
		ans=(ans*qsm(yz[i],f(yz[i]),mod))%mod;//统计求和
	}
	printf("%lld\n",ans%mod);
}

后记

因为一些事情,没能赶上这场比赛。于是后半夜开始补题。
在构筑思路,到代码实现,最后不断改BUG后AC的过程,虽然很长,但真的是很棒的体验。
凌晨三点,在室友都早已深深睡去的时候,屏幕上跳出的“Accept”是属于我一个人的小确幸。
不过,出题人给出的思路似乎复杂度比我的要小,但听群里大佬说可能需要unsigned long long之类的…
今年是笔者打ACM的第一年,希望一切安好,希望自己和队友在接下来的比赛可以拿个牌安享晚年
DrGilbert 2019.9.30

猜你喜欢

转载自blog.csdn.net/oampamp1/article/details/101754305