zoukankan      html  css  js  c++  java
  • BZOJ.4816.[SDOI2017]数字表格(莫比乌斯反演)

    题目链接

    总感觉博客园的(Markdown)很。。(gouzhi),可以看这的

    这个好像简单些啊,只要不犯sb错误
    **[Update] **真的算反演中比较裸的题了...


    (Description)
      用(f[i])表示(Fibonacci)数列的第(i)项,求$$prod_{i=1}^nprod_{j=1}^mf[gcd(i,j)]mod (10^9+7)$$
    (Solution)

    [ egin{aligned} Ans &=prod_{i=1}^nprod_{j=1}^mf[(i,j)]\ &=prod_{d=1}^nprod_{i=1}^nprod_{j=1}^m[(i,j)=d]*f[d]\ &=prod_{d=1}^nf[d]^{sum_{i=1}^nsum_{j=1}^m[(i,j)=d]}\ &=prod_{d=1}^nf[d]^{sum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{m}{d} floor}[(i,j)=1]}\ &=prod_{d=1}^nf[d]^{sum_{i=1}^{min}mu(i)lfloorfrac{n}{id} floorlfloorfrac{m}{id} floor}\ &=prod_{d=1}^nf[d]^{sum_{dmid T}mu(frac{T}{d})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor} end{aligned} ]

      直接去枚举(T)

    [ egin{aligned} Ans &=prod_{d=1}^nf[d]^{sum_{dmid T}mu(frac{T}{d})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor}\ &=prod_{T=1}^nprod_{dmid T}f[d]^{mu(frac{T}{d})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor}\ &=prod_{T=1}^nprod_{dmid T}(f[d]^{mu(frac{T}{d}) })^{lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor} end{aligned} ]

      同之前,枚举约数暴力更新(prod_{dmid T}f[d]^{mu(frac{T}{d})}),复杂度(O(nlog n))((prod_{dmid T}f[frac{T}{d}]^{mu(d)}))。总复杂度(O(nlog n+Tsqrt n))
      注意次幂不能直接取模,利用费马小定理可以对(mod-1)取模。
      然后注意(f[0]=0)。。

    小结:
      套路1:把(prod)换到幂上去,这样就有(sum)了。

      套路2:令(T=id),在最外层枚举(T)

      另外常见的就不再写了。

      F[]用int,FP()中的长式子放到外面,优化还是比较明显有的。


    原先的代码:

    //17912kb	35060ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define mod (1000000007)
    typedef long long LL;
    const int N=1e6+2;
    
    int cnt,P[N>>3],mu[N+2],f[N+2],inv_f[N+2],F[N+2];
    bool Not_p[N+2];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    int FP(LL x,int k)
    {
    	LL t=1;
    	for(; k; k>>=1,x=x*x%mod)
    		if(k&1) t=t*x%mod;
    	return t;
    }
    void Init()
    {
    	mu[1]=f[1]=inv_f[1]=1;//f[0]=0!
    	for(int i=2; i<N; ++i)
    		f[i]=(f[i-1]+f[i-2])%mod, inv_f[i]=FP(f[i],mod-2);
    	for(int i=2; i<N; ++i)
    	{
    		if(!Not_p[i]) P[++cnt]=i,mu[i]=-1;
    		for(int v,j=1; j<=cnt&&(v=i*P[j])<N; ++j)
    		{
    			Not_p[v]=1;
    			if(i%P[j]) mu[v]=-mu[i];
    			else {mu[v]=0; break;}
    		}
    	}
    	for(int i=0; i<N; ++i) F[i]=1;//F[0]=1
    	for(int i=1; i<N; ++i)
    		if(mu[i]==1)
    			for(int d=1,T=0; (T+=i)<N; ++d) F[T]=1ll*F[T]*f[d]%mod;
    		else if(mu[i]==-1)
    			for(int d=1,T=0; (T+=i)<N; ++d) F[T]=1ll*F[T]*inv_f[d]%mod;
    	for(int i=2; i<N; ++i) F[i]=1ll*F[i]*F[i-1]%mod;
    }
    inline int inv(int x){
    	return FP(x,mod-2);
    }
    int Calc(int n,int m)
    {
    	if(n>m) std::swap(n,m);
    	int res=1;
    	for(int nxt,tmp,i=1; i<=n; i=nxt+1){
    		nxt=std::min(n/(n/i),m/(m/i)),
    		tmp=1ll*F[nxt]*inv(F[i-1])%mod,//存次数就没用啦?大概是留一个式子比较好?
    		res=1ll*res*FP(tmp,1ll*(n/i)*(m/i)%(mod-1))%mod;//注意次幂是模(mod-1)。
    	}
    	return res;
    }
    
    int main()
    {
    	Init();
    	int T,n,m; scanf("%d",&T);
    	while(T--)
    		scanf("%d%d",&n,&m),printf("%d
    ",Calc(n,m));
    
    	return 0;
    }
    

    新写的代码(19.2.13):

    /*
    17912kb	33888ms
    注意本题特殊在是次幂=-=:mu[]可能等于-1,即乘一个F[]的逆元;指数要对mod-1取模。
    */
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define mod 1000000007
    #define Mod(x) x>=mod&&(x-=mod)
    typedef long long LL;
    const int N=1e6+2;
    
    int sum[N],F[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now;
    }
    inline int FP(int x,int k)
    {
    	int t=1;
    	for(; k; k>>=1,x=1ll*x*x%mod)
    		if(k&1) t=1ll*t*x%mod;
    	return t;
    }
    void Init()
    {
    	static int cnt,P[N>>3],mu[N],invF[N];
    	static bool notP[N];
    	F[0]=0, F[1]=F[2]=invF[1]=invF[2]=1;
    	for(int i=3; i<N; ++i) F[i]=F[i-1]+F[i-2], Mod(F[i]), invF[i]=FP(F[i],mod-2);
    	mu[1]=1;
    	for(int i=2; i<N; ++i)
    	{
    		if(!notP[i]) P[++cnt]=i, mu[i]=-1;
    		for(int j=1,v; j<=cnt&&(v=i*P[j])<N; ++j)
    		{
    			notP[v]=1;
    			if(i%P[j]) mu[v]=-mu[i];
    			else {mu[v]=0; break;}
    		}
    	}
    	for(int i=0; i<N; ++i) sum[i]=1;//sum[0]=1,因为询问的时候要用到*inv(sum[0]) = =
    	for(int d=1; d<N; ++d)//可以先枚举这个mu[d],就可以在循环外写if了=v= 
    		if(mu[d]==1)
    			for(int T=0,i=1; (T+=d)<N; ++i) sum[T]=1ll*sum[T]*F[i]%mod;
    		else if(mu[d]==-1)
    			for(int T=0,i=1; (T+=d)<N; ++i) sum[T]=1ll*sum[T]*invF[i]%mod;
    	for(int i=2; i<N; ++i) sum[i]=1ll*sum[i]*sum[i-1]%mod;
    }
    
    int main()
    {
    	Init();
    	for(int T=read(); T--; )
    	{
    		const int n=read(),m=read();
    		LL ans=1;
    		for(int i=1,l=std::min(n,m),nxt; i<=l; i=nxt+1)
    		{
    			nxt=std::min(n/(n/i),m/(m/i));
    			ans=ans*FP(1ll*sum[nxt]*FP(sum[i-1],mod-2)%mod,1ll*(n/i)*(m/i)%(mod-1))%mod;
    		}
    		printf("%lld
    ",ans);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    django wsgi nginx 配置
    supervisor error: <class 'socket.error'>, [Errno 110]
    gunicorn 启动无日志
    获取windows 网卡GUID和ip信息
    亚马逊EC2根硬盘空间扩容
    pypcap 安装
    mysql 1709: Index column size too large. The maximum column size is 767 bytes.
    mysql死锁检查
    D3.js画思维导图(转)
    用D3.js画树状图
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8718273.html
Copyright © 2011-2022 走看看