数論+貪欲-Basic Gcd Problem-2020牛客夏休み多校訓練キャンプ(第4回)
タイトル:
与えられた式:
{ f c ( x ) = m a x 1 ≤ i ≤ x − 1 c ⋅ f c ( g c d ( i , x ) ) x > 1 f c ( x ) = 1 x = 1\begin{cases}f_c(x)=max_{1≤i≤x-1}c·f_c(gcd(i,x))\qquad x>1\\\\f_c(x)=1\qquad\qquad\qquad\qquad\qquad\qquad\quad x=1\end{cases} ⎩⎪⎨⎪⎧fc(x)=max1≤i≤x−1c⋅fc(gcd(i,x))x>1fc(x)=1x=1
T組のテストデータであり、各組は2つの正の整数nとcを含み、f c(n)を出力する.答えは1 0 9+7で型を取ります.T組のテストデータ、各組は2つの正の整数nとcを含んで、f_を出力しますc(n).答えは10^9+7で型を取ります.T組のテストデータであり、各組は2つの正の整数nとcを含み、fc(n)を出力する.答えは109+7で型を取ります.
データ範囲:
1 ≤ T ≤ 1 0 6 , 1 ≤ n , c ≤ 1 0 6 1≤T≤10^6,1≤n,c≤10^6 1≤T≤106,1≤n,c≤106
例1入力
2
3 3
10 5
しゅつりょく
3
25
分析:
f反復の回数kが多ければ多いほど良く,答えはc kであることが容易に解析された.f反復の回数kが多ければ多いほど良いと分析しやすく,答えはc^kである.f反復の回数kが多ければ多いほど良いと分析しやすく,答えはckである.
n=P 1 a 1 P 2 a 2を貪欲に考える.P k a kは、P 1
g cdの反復回数を最も多くするには、最小質量因子を毎回約1つ除去することが最適であり、このように総回数、すなわちすべての質量因子指数の和である.gcdの反復回数を最も多くするには、最小質量因子を毎回約1つ除去することが最適であり、このように総回数、すなわちすべての質量因子指数の和である.gcdの反復回数を最も多くするには、最小質量因子を毎回約1つ除去することが最適であり、このように総回数、すなわちすべての質量因子指数の和である.
問題:正の整数nをどのように急速に分解し、そのすべての質因子の指数の和を得るか.
本題T≦1 0 9,n≦1 0 6,n個毎に質量因数を分解すれば,時間複雑度O(n)もタイムアウトする,本題T≦10^9,n≦10^6,n個毎に質量因数を分解すれば,時間複雑度O(sqrt{n})もタイムアウトする,本題T≦109,n≦106,n個毎に質量因数を分解すれば,時間の複雑さがO(n)でもタイムアウトし、
したがって,前処理しか実現できない.したがって,前処理しか実現できない.したがって,前処理しか実現できない.
M[i]は正の整数iの全質量因子の指数の和を表すとする.M[i]は正の整数iのすべての質量因子の指数の和を表すとする.M[i]は正の整数iのすべての質量因子の指数の和を表すとする.
①、iが素数であればM[i]=1.①、iが素数であればM[i]=1とする.①、iが素数であればM[i]=1とする.
②、任意の合数に対して、その最小質量因子P jと別の数iとの積を分解する:P j× i,M[P j]× i ] + = M [ i ] + 1 . ②、任意の合数に対して、その最小質量因子P_を分解するjと他の数iとの積:P_j×i,M[P_j]×i]+=M[i]+1. ②、任意の合数に対して、その最小質量因子Pjと別の数iとの積を分解する:Pj×i,M[Pj]×i]+=M[i]+1.
従って,線形ふるいでM配列を繰返し求めることができる.従って,線形ふるいでM配列を繰返し求めることができる.従って,線形ふるいでM配列を繰返し求めることができる.
コード:
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N=1e6+10, mod=1e9+7;
int primes[N],cnt,M[N];
bool st[N];
void get_prime(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++]=i;
M[i]=1;
}
for(int j=0;primes[j]*i<=n;j++)
{
st[primes[j]*i]=true;
M[primes[j]*i]+=M[i]+1;
if(i%primes[j]==0) break;
}
}
}
int quick_pow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=(ll)res*a%mod;
a=(ll)a*a%mod;
b>>=1;
}
return res;
}
int main()
{
get_prime(1e6);
int T;
int n,c;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&c);
int k=M[n];
printf("%d
",quick_pow(c,k));
}
return 0;
}