zoukankan      html  css  js  c++  java
  • 一些数论函数题

    luogu2257 YY的GCD

    答案为:
    (sumlimits_{pin prime}sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)==p])
    (=sumlimits_{pin prime}sumlimits_{i=1}^{lfloorfrac{n}{p} floor}sumlimits_{j=1}^{{lfloorfrac{m}{p}} floor}[gcd(i,j)==1])
    (=sumlimits_{pin prime}sumlimits_{i=1}^{lfloorfrac{n}{p} floor}sumlimits_{j=1}^{{lfloorfrac{m}{p}} floor}sumlimits_{t mid iland tmid j}mu(t))
    (=sumlimits_{pin prime}sumlimits_{t=1}^{min(n,m)}mu(t)sumlimits_{i=1}^{lfloorfrac{n}{pt} floor}sumlimits_{j=1}^{{lfloorfrac{m}{pt}} floor}1)
    (=sumlimits_{pin prime}sumlimits_{t=1}^{min(n,m)}mu(t)lfloorfrac{n}{pt} floorlfloorfrac{m}{pt} floor)
    (T=pt)
    原式(=sumlimits_{pin prime}sumlimits_{t=1}^{min(n,m)}mu(t)lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor)
    (=sumlimits_{T=1}^{min(n,m)}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsumlimits_{pin prime land pmid T}mu(frac{T}{p}))
    前面的(sumlimits_{T=1}^{min(n,m)}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor)就是一个整除分块。这就需要我们求出(sumlimits_{pin prime land pmid T}mu(frac{T}{p}))的前缀合,我们枚举p然后遍历值域就是调和级数复杂度的预处理。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int mu[10000002],prim[1000000],vis[10000002],g[10000002],sum[10000002],cnt,n[10100],m[10100],t;
    long long ans;
    inline void read(int &x)
    {
        x=0;
        static int p;p=1;
        static char c;c=getchar();
        while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
        x*=p;   
    }
    void getmu(int n){
    	mu[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!vis[i]){
    			prim[++cnt]=i; 
    			mu[i]=-1;
    		}
    		for(int j=1;i*prim[j]<=n;j++){
    			vis[i*prim[j]]=1;
    			if(i%prim[j]==0)break;
    			else mu[i*prim[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=cnt;i++)
    		for(int j=1;j*prim[i]<=n;j++)
    			g[j*prim[i]]+=mu[j];
    	for(int i=1;i<=n;i++)
    		sum[i]=sum[i-1]+g[i];
    }
    int main(){
    	read(t);
    	int tot=0;
    	for(int i=1;i<=t;i++){
    		read(n[i]);read(m[i]);
    		tot=max(tot,max(n[i],m[i]));
    	}
    	getmu(tot);
    	for(int i=1;i<=t;i++){
    		ans=0;
    		if(n[i]>m[i])swap(n[i],m[i]);
    		for(int l=1,r;l<=n[i];l=r+1){
    			r=min(n[i]/(n[i]/l),m[i]/(m[i]/l));
    			ans+=(long long)(n[i]/l)*(m[i]/l)*(sum[r]-sum[l-1]);
    		} 
    		printf("%lld
    ",ans);
    	}
    	return 0;	
    } 
    

    [CQOI2015]选数

    显然是一道莫比乌斯反演。
    设f[i]为选出n个数gcd为i的方案数。
    设F[i]为选出n个数gcd为i的倍数的方案数。
    把L,H都除去k,答案就是f[1](注意一点除的时候当L%k!=0是L除完k之后还要加1)。
    然后有(F[i]=sumlimits_{i mid d }f[d])
    (f[i]=sumlimits_{i mid d} mu(frac{d}{i})F[d])
    应为我们要求的是f[1],
    (f[1]=sumlimits_d mu(d)F[d])
    F怎么求就是可以选的数的n次方:((lfloorfrac{H}{k} floor-lfloorfrac{L-1}{k} floor)^n)
    (mu)前缀和用杜教筛就行了。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<map>
    using namespace std;
    #define int long long
    map<int,bool>vis;
    map<int,int> hsh;
    const int N=2001000;
    const int p=1e9+7;
    int mu[N],book[N],prime[N],cnt,n,k,L,H;
    int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return sum*f;
    }
    void pre_work(){
    	mu[1]=1;
    	for(int i=2;i<=1000000;i++){
    		if(book[i]==0){
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&prime[j]*i<=1000000;j++){
    			book[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=1000000;i++)mu[i]+=mu[i-1];
    }
    int sum(int x){
    	if(x<=1000000)return mu[x];
    	if(vis[x]==1)return hsh[x];
    	int tmp=1;
    	for(int l=2,r;l<=x;l=r+1){
    		r=(x/(x/l));
    		tmp=tmp-(r-l+1ll)*sum(x/l)%p;
    		tmp=(tmp%p+p)%p;
    	}
    	vis[x]=1;hsh[x]=tmp;
    	return tmp;
    }
    int ksm(int x,int b){
    	int tmp=1;
    	while(b){
    		if(b&1)tmp=tmp*x%p;
    		b>>=1;
    		x=x*x%p;
    	}
    	return tmp;
    }
    int work(){
    	int tmp=0;
    	for(int l=1,r;l<=H;l=r+1){
    		if(l>L-1ll)r=H/(H/l);
    		else r=min(H/(H/l),(L-1ll)/((L-1ll)/l)); 
    		tmp=tmp+(sum(r)-sum(l-1ll))*ksm((H/l-(L-1ll)/l),n)%p;
    		tmp=(tmp%p+p)%p;
    	}
    	return tmp;
    }
    signed main(){
    	pre_work();
    	n=read();k=read();L=read();H=read();
    	if(L%k)L=L/k+1;
    	else L=L/k;
    	H=H/k;
    	printf("%lld",work());
    	return 0;
    }
    

    BZOJ 4176 Lucas的数论

    enter image description here
    ((n leq 1e9))f代表约数个数。
    (f(ij)=sumlimits_{x mid i }sumlimits_{ ymid j}[gcd(x,y)==1])
    我有一个精巧的证明可惜这里地方太小,写不下。
    (我才知道这是费马说的,思维风暴证明费马大定理?)
    我才没有什么精巧的证明,我会暴力。
    因为约束个数函数是极性函数,把每一个质因子分开考虑。
    设ij中有(p^k),i中有(p^a),j中有(p^b),其中a+b=k。
    然后我们惊奇的发现(p^k)的约数个数为k+1=a+b+1。然后(p^a),和(p^b)互质的情况有a+b+1。
    然后就可以嘿嘿嘿了。
    原式等于:(sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}sumlimits_{x mid i }sumlimits_{ ymid j}[gcd(x,y)==1])
    (=sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}sumlimits_{x mid i }sumlimits_{ymid j}sumlimits_{tmid xland tmid y}mu(t))
    (=sumlimits_{t=1}^{n}mu(t)sumlimits_{x=1}^{lfloorfrac{n}{t} floor}lfloorfrac{n}{tx} floorsumlimits_{y=1}^{lfloorfrac{n}{t} floor}lfloorfrac{n}{ty} floor)
    (=sumlimits_{t=1}^{n}mu(t) (sumlimits_{x=1}^{ lfloor frac{n}{t} floor} lfloorfrac{n}{tx} floor)^2)
    然后上整除分块。
    复杂度。。听说是(O(sqrt{n}logsqrt{n}))

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define int long long
    const int p=1e9+7;
    const int N=1010000;
    map<int,int>hsh;
    map<int,bool>vis;
    int mu[N],book[N],prime[N],cnt,n;
    void pre_work(){
    	mu[1]=1;
    	for(int i=2;i<=1000000;i++){
    		if(book[i]==0){
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&prime[j]*i<=1000000;j++){
    			book[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=1000000;i++)mu[i]+=mu[i-1];
    }
    int work(int x){
    	int tmp=0;
    	for(int l=1,r;l<=x;l=r+1){
    		r=x/(x/l);
    		tmp=(tmp+(r-l+1)*(x/l)%p)%p;
    	}
    	return tmp;
    }
    int sum(int x){
    	if(x<=1000000)return mu[x];
    	if(vis[x])return hsh[x];
    	int tmp=1;
    	for(int l=2,r;l<=x;l=r+1){
    		r=x/(x/l);
    		tmp=tmp-sum(x/l)*(r-l+1);
    		tmp=(tmp%p+p)%p;
    	}
    	vis[x]=1;hsh[x]=tmp;
    	return tmp;
    }
    int calc(int x){
    	int tmp=0;
    	for(int l=1,r;l<=x;l=r+1){
    		r=x/(x/l);
    		int w=work(x/l);
    		tmp=tmp+(sum(r)-sum(l-1))*w%p*w%p;
    		tmp=(tmp%p+p)%p;
    	}
    	return tmp;
    }
    int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return sum*f;
    }
    signed main(){
    	n=read();
    	pre_work();
    	printf("%lld",calc(n));
    	return 0;
    }
    

    luogu P3768 简单的数学题

    (sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}ijgcd(i,j))
    gcd不仅可以化成(mu)
    原式等于
    (sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}ijsumlimits_{t mid i land t mid j} varphi(t))
    为什么?
    因为(varphi*1)=id
    然后接着化简。
    (sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}ijsumlimits_{t mid i land t mid j} varphi(t))
    (=sumlimits_{t=1}^{n}varphi(t)*t^2sumlimits_{i=1}^{lfloorfrac{n}{t} floor}sumlimits_{j=1}^{lfloorfrac{n}{t} floor}ij)
    (=sumlimits_{t=1}^{n}varphi(t)*t^2(sumlimits_{i=1}^{lfloorfrac{n}{t} floor}i)^2)
    (=sumlimits_{t=1}^{n}varphi(t)*t^2sumlimits_{i=1}^{lfloorfrac{n}{t} floor}i^3)
    然后就可以做了。
    最后一步怎么化简?暴力展开。。。
    然后上杜教筛就行了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define int long long
    const int p=1e9+7;
    const int N=1010000;
    map<int,int>hsh;
    map<int,bool>vis;
    int mu[N],book[N],prime[N],cnt,n;
    void pre_work(){
    	mu[1]=1;
    	for(int i=2;i<=1000000;i++){
    		if(book[i]==0){
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&prime[j]*i<=1000000;j++){
    			book[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=1000000;i++)mu[i]+=mu[i-1];
    }
    int work(int x){
    	int tmp=0;
    	for(int l=1,r;l<=x;l=r+1){
    		r=x/(x/l);
    		tmp=(tmp+(r-l+1)*(x/l)%p)%p;
    	}
    	return tmp;
    }
    int sum(int x){
    	if(x<=1000000)return mu[x];
    	if(vis[x])return hsh[x];
    	int tmp=1;
    	for(int l=2,r;l<=x;l=r+1){
    		r=x/(x/l);
    		tmp=tmp-sum(x/l)*(r-l+1);
    		tmp=(tmp%p+p)%p;
    	}
    	vis[x]=1;hsh[x]=tmp;
    	return tmp;
    }
    int calc(int x){
    	int tmp=0;
    	for(int l=1,r;l<=x;l=r+1){
    		r=x/(x/l);
    		int w=work(x/l);
    		tmp=tmp+(sum(r)-sum(l-1))*w%p*w%p;
    		tmp=(tmp%p+p)%p;
    	}
    	return tmp;
    }
    int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return sum*f;
    }
    signed main(){
    	n=read();
    	pre_work();
    	printf("%lld",calc(n));
    	return 0;
    }
    

    [SDOI2017]数字表格

    (Pi_{i=1}^{n}Pi_{j=1}^{m}f[gcd(i,j)])

    (=Pi_{d=1} f[d]^{sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{n}{d} floor}[gcd(i,j)==1]})
    (=Pi_{d=1} f[d]^{sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{n}{d} floor}sumlimits_{t mid iland tmid j}mu(t)})
    (=Pi_{d=1} f[d]^{sumlimits_{i=1}^{min(n,m)}mu(t)lfloorfrac{n}{dt} floorlfloorfrac{m}{dt} floor})
    令T=dt
    (=Pi_{T=1}^{min(m,n)}Pi_{dmid T} f[d]^{mu(frac{T}{d})lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor})
    然后我们把(lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor)分块。(Pi_{dmid T} f[d]^{mu(frac{T}{d})})预处理。因为调和级数复杂度可以接受。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define int long long
    const int mod=1e9+7;
    const int N=1010100;
    int mu[N],book[N],prime[N],cnt,f[N],T,n,m,F[N],inv[N];
    int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return sum*f;
    }
    int ksm(int x,int b){
    	int tmp=1;
    	while(b){
    		if(b&1)tmp=tmp*x%mod;
    		b>>=1;
    		x=x*x%mod;
    	}
    	return tmp;
    }
    void pre_work(){
    	mu[1]=1;
    	for(int i=2;i<=1000000;i++){
    		if(book[i]==0){
    			mu[i]=-1;
    			prime[++cnt]=i;
    		}
    		for(int j=1;j<=cnt&&i*prime[j]<=1000000;j++){
    			book[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    	f[0]=0;f[1]=1;
    	for(int i=2;i<=1000000;i++)
    		f[i]=(f[i-1]+f[i-2])%mod;
    	for(int i=0;i<=1000000;i++)F[i]=1;
    	for(int i=1;i<=1000000;i++)
    		for(int j=1;j*i<=1000000;j++){
    			int tmp;
    			if(mu[j]==0)tmp=1;
    			else if(mu[j]==1)tmp=f[i];
    			else tmp=ksm(f[i],mod-2);
    			F[i*j]=(F[i*j]*tmp)%mod;
    		}
    	for(int i=2;i<=1000000;i++)F[i]=(F[i-1]*F[i])%mod;
    	for(int i=1;i<=1000000;i++)inv[i]=ksm(F[i],mod-2);
    	inv[0]=1;
    }
    int work(int n,int m){
    	if(n>m)swap(n,m);
    	int tmp=1;
    	for(int l=1,r;l<=n;l=r+1){
    		r=min(m/(m/l),n/(n/l));
    		tmp=(tmp*ksm(F[r]*inv[l-1]%mod,(n/l)*(m/l)))%mod;
    	}
    	return tmp;
    }
    signed main(){
    	T=read();
    	pre_work();
    	while(T--){
    		n=read(),m=read();
    		printf("%lld
    ",work(n,m));
    	}
    	return 0;
    }
    
  • 相关阅读:
    robotframework安装与配置--学习第一天
    Google chrome浏览器打不开网页,显示ERR_Failed...等问题的解决方法
    解决dos窗口乱码问题
    打印风车旋转效果
    spring Security 得到认证用户名的方法
    spring requestmapping 拦截多个请求
    github多人协同使用。
    Spring boot Security 用于权限管理,用户添加等。
    spring boot上传 下载图片。
    mysql修改数据库编码(数据库字符集)和表的字符编码的方法
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/10262443.html
Copyright © 2011-2022 走看看