• [BZOJ2627][洛谷P4464]JZPKIL(莫比乌斯反演+Pollard-rho+伯努利数)


    题面

    https://www.luogu.com.cn/problem/P4464

    题解

    前置知识

    本题要求({sum_{i=1}^{n}}(i,n)^x[i,n]^y)。上手即反演:

    [={sumlimits_{i=1}^{n}}(i,n)^{x-y}i^yn^y ]

    [=n^y{sumlimits_{i=1}^{n}}i^y(i,n)^{x-y} ]

    [=n^y{sumlimits_{i=1}^{n}}i^y{sumlimits_{d|(i,n)}}g(d) ]

    其中,

    [g(d)={sumlimits_{p|d}}{mu(p)}({frac{d}{p}})^{x-y} ]

    [原式=n^y{sumlimits_{d|n}}g(d){sumlimits_{i=1}^{n}}i^y[d|i] ]

    [=n^y{sumlimits_{d|n}}g(d)d^y{sumlimits_{i=1}^{frac{n}{d}}}i^y ]

    利用伯努利数,有

    [{sumlimits_{i=1}^{frac{n}{d}}}i^y={frac{1}{y+1}}{sumlimits_{i=0}^{y}}{ binom{y+1}{i}}B_i(frac{n}{d})^{y+1-i} ]

    所以原式=

    [n^y*{frac{1}{y+1}}*{sumlimits_{i=0}^{y}}{ binom{y+1}{i}}B_i{sumlimits_{d|n}}g(d)d^y(frac{n}{d})^{y+1-i} ]

    [=n^y*{frac{1}{y+1}}*{sumlimits_{i=0}^{y}}{ binom{y+1}{i}}B_in^{y+1-i}{sumlimits_{d|n}}g(d)d^{i-1} ]

    前面两项均为常数;由于伯努利数满足

    [B_i=egin{cases} 1(i=0) \ 1-{sumlimits_{j=0}^{i-1}}B_j{ binom{i+1}{j}}{frac{1}{i+1}} end{cases} ]

    的递推式,所以所有的(B_i)可以(O(y^2))预处理出来,也变成了常数。所以问题的瓶颈就落在了计算({sum_{d|n}}g(d)d^{i-1})上。由于前面已经循环过i=0到y,并且还有T组数据,所以这里必须在最多(O(log n))内解决。不过,我们能够看出(g(d)d^{i-1})是一个积性函数。所以,设它是(h(d)),并设n的素因数分解式是({prod_{i=1}^{k}}p_k^{alpha_{k}}),就可以完成下列转化:

    [{sumlimits_{d|n}}h(d) ]

    [={prodlimits_{l=1}^{k}}{sumlimits_{j=0}^{alpha_l}}h(p_l^{j}) ]

    现在我们再拆开h。

    [h(d)=g(d)d^{i-1} ]

    [={sumlimits_{e|d}}{mu(e)}(frac{d}{e})^{x-y}d^{i-1} ]

    对于质数p和自然数j,发现

    [h(p^j)=egin{cases} 1(j=0) \ p^{j(x-y+i-1)}-p^{j(x-y+i-1)+y-x} end{cases}(j{geq}1) ]

    而且,(x-y+i-1)(y-x)都处于([-3001,6000])的范围之中,这意味着我们可以对于所有的n的质因子p,预处理出p的-3001到6000次方,这样的预处理总时间是(O(Tlog n*y)),可以接受。在j>1的时候,只需要乘上(p^{x-y+i-1}),就可以从(h(p^{j-1}))转移过来了。

    于是,计算({sum_{d|n}}h(d))的时间复杂度降为了(O({sum}{alpha_i}))(O(log n))

    过程中,需要对n做素因数分拆;由于n过大,所以需要使用Pollard-rho配合Miller-rabin实现,其时间复杂度约为(O(n^{frac{1}{4}}))

    总时间复杂度(O(Tn^{frac{1}{4}}+Tylog n+y^2))

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    #define ld long double
    #define rg register
    #define M 3000
    #define Mod 1000000007
    
    namespace ModCalc{
    	inline void Inc(ll &x,ll y,ll mod){
    		x += y;if(x >= mod)x -= mod;
    	}
    	
    	inline void Dec(ll &x,ll y,ll mod){
    		x -= y;if(x < 0)x += mod;
    	}
    	
    	inline void Adjust(ll &x,ll mod){
    		x = (x % mod + mod) % mod;
    	}
    	
    	inline void Tms(ll &x,ll y,ll mod){ //O(1)快速乘 
    		x = x * y - (ll)((ld)x * y / mod + 1e-3) * mod;
    		Adjust(x,mod);
    	}
    	
    	inline ll Add(ll x,ll y,ll mod){
    		Inc(x,y,mod);return x;
    	}
    	
    	inline ll Sub(ll x,ll y,ll mod){
    		Dec(x,y,mod);return x;
    	}
    	
    	inline ll Check(ll x,ll mod){
    		Adjust(x,mod);return x;
    	}
    	
    	inline ll Mul(ll x,ll y,ll mod){
    		Tms(x,y,mod);return x;
    	}
    }
    using namespace ModCalc;
    
    inline ll read(){
    	ll s = 0,ww = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    	return s * ww;
    }
    
    inline ll power(ll a,ll n,ll mod){
    	ll x = a,s = 1;
    	while(n){
    		if(n & 1)Tms(s,x,mod);
    		Tms(x,x,mod);
    		n >>= 1;
    	}	
    	return s;
    }
    
    ll B[M+5],b[M+5];
    ll jc[M+5],iv[M+5]; //阶乘和阶乘的逆元 
    
    inline void prepro(){ //预处理jc,iv 
    	jc[0] = 1;
    	for(rg ll i = 1;i <= M + 1;i++)jc[i] = jc[i-1] * i % Mod;
    	iv[M+1] = power(jc[M+1],Mod - 2,Mod);
    	for(rg ll i = M;i >= 0;i--)iv[i] = iv[i+1] * (i + 1) % Mod;
    }
    
    inline void calcB(){
    	B[0] = 1;
    	for(rg ll i = 1;i <= M;i++){
    		ll cur = 0;
    		for(rg ll j = 0;j < i;j++)Inc(cur,jc[i+1] * iv[j] % Mod * iv[i+1-j] % Mod * B[j] % Mod,Mod); 
    		cur = cur * jc[i] % Mod * iv[i+1] % Mod;
    		B[i] = Sub(1,cur,Mod);
    	}
    }
    
    inline ll test(ll p,ll n){
    	if(n == p)return 1;
    	ll m = n - 1;
    	while(!(m & 1))m >>= 1;
    	ll x = power(p,m,n);
    	if(x == 1)return 1;
    	for(;m < n - 1;m <<= 1){
    		ll y = Mul(x,x,n);
    		if(y == 1)return x == n - 1; 
    		x = y;
    	}
    	return 0;
    }
    
    ll pri[9] = {2,3,5,7,11,13,17,19,23};
    
    inline ll MR(ll n){ //Miller-rabin
    	if(n < 2)return 0;
    	if(!(n & 1))return n == 2;
    	for(rg ll i = 0;i < 9;i++)if(!test(pri[i],n))return 0;
    	return 1;
    }
    
    inline ll f(ll x,ll c,ll mod){
    	return Add(Mul(x,x,mod),c,mod);
    }
    
    inline ll gcd(ll a,ll b){
    	return b ? gcd(b,a % b) : a;
    }
    
    inline ll PR(ll n){ //Pollard-rho
    	ll c = 1ll * rand() % (n - 1) + 1,x = 0,y = 0,prod = 1;
    	for(rg ll step = 1;;step <<= 1){
    		for(rg ll i = 1;i <= step;i++){
    			y = f(y,c,n);
    			Tms(prod,abs(x-y),n);
    			if(i % 127 == 0){
    				ll d = gcd(prod,n);
    				if(d > 1)return d;
    			}
    		}
    		ll d = gcd(prod,n);
    		if(d > 1)return d;
    		x = y;
    	}
    }
    
    vector<ll>fac; //PR算法分拆出的无序质因子 
    vector<pair<ll,ll> >Pfac; //整理好后的质因子和对应的次数 
    
    inline void divide(ll n){ //分拆n 
    	if(n == 1)return;
    	if(MR(n)){
    		fac.push_back(n);
    		return;
    	}
    	ll d = PR(n);
    	while(d == n)d = PR(n);
    	divide(d);
    	divide(n / d);
    }
    
    ll pw[60+5][3*M+5]; //n的所有素因子的-3001~6000次方 
    
    int main(){
    	srand((int)time(NULL));
    	prepro();
    	calcB();
    	ll T = read();
    	while(T--){
    		ll n = read(),x = read(),y = read();
    		fac.resize(0);
    		Pfac.resize(0);
    		divide(n);
    		sort(fac.begin(),fac.end());
    		ll p = 0,v = 0;
    		for(rg ll i = 0;i < fac.size();i++){
    			if(fac[i] != p){
    				if(p)Pfac.push_back(make_pair(p,v));
    				p = fac[i],v = 1;
    			}
    			else v++;
    		}
    		if(p)Pfac.push_back(make_pair(p,v));
    		for(rg ll i = 0;i < Pfac.size();i++){ //预处理pw 
    			ll p = Pfac[i].first,vp = power(p % Mod,Mod - 2,Mod);
    			pw[i][3001] = 1;
    			for(rg ll j = 1;j <= 6000;j++)pw[i][j+3001] = pw[i][j+3000] * (p % Mod) % Mod;
    			for(rg ll j = -1;j >= -3001;j--)pw[i][j+3001] = pw[i][j+3002] * vp % Mod;
    		}
    		ll ans = 0;
    		for(rg ll i = 0;i <= y;i++){
    			ll b = B[i] * jc[y] % Mod * iv[i] % Mod * iv[y+1-i] % Mod;
    			b = b * power(n % Mod,y + 1 - i,Mod) % Mod;
    			for(rg ll l = 0;l < Pfac.size();l++){
    				ll s = 1,w = pw[l][x-y+i-1+3001];
    				ll cur = Sub(1,pw[l][y-x+3001],Mod);
    				for(rg ll j = 1;j <= Pfac[l].second;j++){
    					cur = cur * w % Mod;
    					Inc(s,cur,Mod);
    				}
    				b = b * s % Mod;
    			}
    			Inc(ans,b,Mod);
    		}
    		ans = ans * power(n % Mod,y,Mod) % Mod;
    		cout << ans << endl;
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    SQL Server 2005技术内幕:查询、调整和优化2——Bookmark Lookup
    隐藏文字用图片代替方案
    检索get参素
    a:hover之后ie6要恢复原来的状态需要hover的时候改变a的状态
    暂记
    台式机搭建wifi热点
    多行文本垂直居中
    chrome上做web app开发 模拟不同的分辨率和设备
    工厂模式和构造函数
    字符串替换
  • 原文地址:https://www.cnblogs.com/xh092113/p/12296807.html
Copyright © 2020-2023  润新知