CF757E Bash Plays with Functions(积性函数)

CF757E Bash Plays with Functions

Statement

  • f 0 ( n ) = ∑ p ⋅ q = n [ gcd ⁡ ( p , q ) = 1 ] f_0(n)=\sum\limits_{p\cdot q=n}[\gcd(p,q)=1] f0(n)=pq=n[gcd(p,q)=1]
  • f r + 1 ( n ) = ∑ u ⋅ v = n f r ( u ) + f r ( v ) 2 f_{r+1}(n)=\sum\limits_{u\cdot v=n}\frac{f_r(u)+f_r(v)}{2} fr+1(n)=uv=n2fr(u)+fr(v)

q ( 1 ≤ q ≤ 1 0 6 ) q(1\leq q\leq10^6) q(1q106)次询问, 每次询问输出 f r ( n )  mod  1 0 9 + 7 ( 0 ≤ r ≤ 1 0 6 , 1 ≤ n ≤ 1 0 6 ) f_r(n)\text{ mod }10^9+7(0\leq r\leq10^6,1\leq n\leq10^6) fr(n) mod 109+7(0r106,1n106).

Solution

n = ∏ i = 1 k p i α k n=\prod_{i=1}^kp_i^{\alpha_k} n=i=1kpiαk u = ∏ i = 1 k p i β i u=\prod_{i=1}^kp_i^{\beta_i} u=i=1kpiβi v = ∏ i = 1 k p i α i − β i v=\prod_{i=1}^kp_i^{\alpha_i-\beta_i} v=i=1kpiαiβi, 满足 n = u × v , ∀ k ∈ [ 1 , k ] , p i n=u\times v,\forall k\in[1,k],p_i n=u×v,k[1,k],pi是质数.

  • 性质1:则显然有 gcd ⁡ ( u , v ) = 1 \gcd(u,v)=1 gcd(u,v)=1的充要条件是 ∀ i ∈ [ 1 , k ] \forall i\in[1,k] i[1,k]满足 β i = 0 或 α i − β i = 0 \beta i=0或\alpha_i-\beta_i=0 βi=0αiβi=0.
  • 性质2: 由性质1可得 f 0 ( ∏ i = 1 k p i α k ) = 2 k f_0(\prod_{i=1}^kp_i^{\alpha_k})=2^k f0(i=1kpiαk)=2k, 即要么 β i = 0 \beta_i=0 βi=0要么 α i − β i = 0 \alpha_i-\beta_i=0 αiβi=0 2 k 2^k 2k种不同的方案数.
  • 性质3: f r + 1 ( n ) = ∑ u ⋅ v = n f r ( u ) + f r ( v ) 2 = ∑ d ∣ n f r ( d ) f_{r+1}(n)=\sum\limits_{u\cdot v=n}\frac{f_r(u)+f_r(v)}{2}=\sum\limits_{d|n}f_r(d) fr+1(n)=uv=n2fr(u)+fr(v)=dnfr(d).
    • 证明: 显然 u ≤ v u\leq v uv是成对出现的. 对于每一个因子 u u u都会被计算两次.
  • 性质4: f r ( n ) f_{r}(n) fr(n)对任意 r ≥ 0 r\geq0 r0都满足 f r ( n ) f_r(n) fr(n)是积性函数.
  • 性质5: f r ( p α ) = ∑ i = 0 α f r − 1 ( p i ) f_r(p^\alpha)=\sum_{i=0}^\alpha f_{r-1}(p^i) fr(pα)=i=0αfr1(pi).

显然 f r ( p α ) f_r(p^\alpha) fr(pα) p p p是具体那个素数是无关的. 我们不妨记录 g i , j = f i ( p j ) g_{i,j}=f_i(p^j) gi,j=fi(pj)的答案.有 g 0 , 0 = 1 , g 0 , i = 2 ( i > 1 ) g_{0,0}=1,g_{0,i}=2(i>1) g0,0=1,g0,i=2(i>1). g i , j = ∑ k = 0 j g i − 1 , j g_{i,j}=\sum_{k=0}^jg_{i-1,j} gi,j=k=0jgi1,j. 我们预处理出 g i , j g_{i,j} gi,j时间复杂度为 O ( 20 n ) O(20n) O(20n).

然后我们用线性筛法计算出, 每个数的质因子分解即可. 时间复杂度 O ( n ) O(n) O(n). 此处可以利用欧拉筛法, 因为欧拉筛法每个素数只会被最小质数筛到, 每个数被筛到时, 我们记录一下这是不是新的质因子, 如果是往结尾加 1 1 1, 否则将最后一个数出现次数 + 1 +1 +1即可.

Code

# define Fast_IO std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
# include "unordered_map"
# include "algorithm"
# include "iostream"
# include "cstdlib"
# include "cstring"
# include "cstdio"
# include "vector"
# include "bitset"
# include "queue"
# include "cmath"
# include "ctime"
# include "map"
# include "set"
# define ll long long
# define ld long double
# define rep1(i,a,b) for(ll i=(a);i<=(b);i++)
# define rep2(i,a,b) for(ll i=(a);i>=(b);i--)
# define pii pair<int,int>
# define pll pair<ll,ll>
# define pb push_back
# define eb emplace_back
# define vi vector<int>
# define vll vector<ll>
# define vpi vector<pii >
# define vpll vector<pll >
# define ri(x) scanf("%d",&x)
# define rf(x) scanf("%f",&x)
# define rl(x) scanf("%lld",&x)
# define rd(x) scanf("%lf",&x)
# define rs(s) scanf("%s",s+1)
# define wi(x) printf("%d",x)
# define wl(x) printf("%lld",x)
# define ws(s) printf("%s",s+1)
# define resize(v,x) v.resize(x)
# define all(v) v.begin(),v.end()
# define reverse(v) reverse(all(v))
# define fi first
# define se second
# define lowbit(x) ((x)&(-(x)))
# define repauto(Name,v) for(auto Name:v)
using namespace std;
template<class I> inline I GCD(I A,I B){return B?GCD(B,A%B):A;}
template<class I> inline I LCM(I A,I B){return A/GCD(A,B)*B;}
template<class I> I Sqrt(I N){
	I sqrtN=sqrt(N)-1;
	while(sqrtN+1<=N/(sqrtN+1))sqrtN++;
	return sqrtN;
}
template<class I> I Pow(I X,I Y,__int128 Mod1=998244353){
	static __int128 Ans; Ans=1;
	for(;Y;Y>>=1,X=(__int128)X*X%Mod1) if(Y&1) Ans=Ans*X%Mod1;
	return Ans;
}
const int Mod=1e9+7;

const int maxm=1e6+10;

int T,R,N;
int F[maxm][21];
long long Ans,Sum;

namespace Count_Divisor_Number_Class{
	int Prime_Cnt;
	int *Prime=new int;
	int *Visit=new int;
	int *Num=new int;
	vi Cnt[maxm];
	inline void Init(int N){
		static int i,j,Now;
		delete Visit;	Visit=new int[N+1]();
		delete Prime;	Prime=new int[N+1]();
		delete Num;		Num=new int[N+1]();
		for(Prime_Cnt=0,Cnt[1].push_back(1),i=2;i<=N;i++){
			if(!Visit[i]) Prime[++Prime_Cnt]=i,Cnt[i].push_back(1),Num[i]=1,Visit[i]=i;
			for(j=1;j<=Prime_Cnt && Prime[j]<=Visit[i] && Prime[j]<=N/i;j++){
				Now=i*Prime[j],Visit[Now]=Prime[j];
				Cnt[Now]=Cnt[i];
				if(!(i%Prime[j])){
					Cnt[Now][Cnt[Now].size()-1]+=1;
				}else Cnt[Now].push_back(1);
			}
		}return;
	}
}using namespace Count_Divisor_Number_Class;

int main(){
# ifdef LH_Frank
    freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
# endif
	Init(1000000);
	F[0][0]=1;
	rep1(i,1,20) F[0][i]=2;
	rep1(i,1,1000000){
		Sum=0;
		rep1(j,0,20){
			Sum=(Sum+F[i-1][j])%Mod;
			F[i][j]=Sum;
		}
	}
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&R,&N);
		Ans=1;
		if(N==1){
			printf("1\n");
			continue;
		}
		repauto(Now,Cnt[N]){
			Ans=Ans*F[R][Now]%Mod;
		}printf("%lld\n",Ans);
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值