zoukankan      html  css  js  c++  java
  • 洛谷 P4844 LJJ爱数数

    题目链接

    显然,我们要找到 (i)(j),使 (gcd(i,j)=1),构造出的方案为 ((i^2+ij,j^2+ij,ij))((j^2+ij,i^2+ij,ij))

    这里我们令 (i geq j),则方案个数为

    (sumlimits_{i=1}^n{sumlimits_{j=1}^i{[gcd(i,j)=1][i^2+ij leq n]}})

    对于 (i^2+ij leq n),我们求出 (j leq frac{n}{i}-i),再解 (frac{n}{2}-i geq 0),得 (i leq sqrt{n}),把式子改一下:

    (sumlimits_{i=1}^{sqrt{n}}{sumlimits_{j=1}^{min (frac{n}{i}-i,i)}{[gcd(i,j)=1]}})

    好哒,我们再看一看 (frac{n}{i}-i=i),解得 (i=sqrt{frac{n}{2}}),分情况讨论:

    (i leq sqrt{frac{n}{2}}) 时,就等价于统计 (sumlimits_{j=1}^{i}{[gcd(i,j)=1]}),线性筛 (phi) 即可。

    (sqrt{frac{n}{2}} < i leq sqrt{n}) 时,(j leq i),这个时候怎么办呢?

    我们暴力容斥就好啦,线性筛时顺便筛出每个数的最小质因子,分解,设有 (K) 个不同的质因子,则 (j) 内与 (i) 互质的数有:

    (j-sumlimits_{k=1}^{K}{(-1)^k*f(k)})(f(k)=sumlimits_{a_1<a_2< cdots <a_k leq K}{frac{j}{prodlimits_{i=1}^{k}{p_{a_i}}}})

    最后把输出 (2ans-1),再加上两个剪枝,就可以轻松跑过啦~

    (frak{code:})

    #include<bits/stdc++.h>
    #define IL inline
    #define LL long long
    using namespace std;
    const int N=1e6+3;
    int vis[N],pri[N],mu[N],a[N],now,num;
    LL n,m,res,Max,ans,phi[N];
    void init(int n){  //线性筛~ 
    	phi[1]=mu[1]=1;
    	for(int i=2;i<=n;++i){
    		if(!vis[i]) vis[i]=i,pri[++pri[0]]=i,phi[i]=i-1,mu[i]=-1;
    	  for(int j=1,k;(k=i*pri[j])<=n;++j){
    	    vis[k]=pri[j];
    	    if(i%pri[j]) mu[k]=-mu[i],phi[k]=phi[i]*phi[pri[j]];
    	    else{phi[k]=phi[i]*pri[j];break;}
    		}
    	}
    }
    void calc(int n){ //分解质因数~ 
    	a[0]=0;
    	while(n^1){
    		if(vis[n]^a[a[0]]) a[++a[0]]=vis[n];
    		n/=vis[n];
    	}
    }
    void dfs(int k,int kk,int val,int op){ //搜索组合方案~ 
    	if(kk==num){ans+=op*(now/val);return;}
    	if(a[0]-k+1<num-kk) return; //显而易见的剪枝1~ 
    	dfs(k+1,kk+1,val*a[k],op);
    	dfs(k+1,kk,val,op); 
    }
    int main()
    {
    	scanf("%lld",&n);init(1e6);
    	m=sqrt(1.0*n/2),Max=sqrt(n);
    	for(int i=1;i<=m;++i) ans+=phi[i];
    	for(int i=m+1,k;i<=Max;++i){
    	  now=n/i-i;int res=ans;
    	  calc(i),ans+=now;
    	  for(num=1,k=a[num];num<=a[0];++num,k*=a[num]){
    	  	if(k>now) break; //显而易见的剪枝2,如果最小的num个质因子相乘大于now,则之后的贡献都为0~ 
    	  	dfs(1,0,1,num&1?-1:1);
    		}
    	}
    	cout<<ans*2-1<<endl; //(2,2,1)会被算2次,所以减1~ 
    	return 0;
    }
    
    
  • 相关阅读:
    解决全局变量共享---C语言的extern关键字用法
    VIM学习笔记
    测试博客
    docker容器中安装vi
    docker中安装Jenkins
    Jenkins Pipeline+Maven+Gitlab持续集成构建问题集锦
    jenkinsapi操作Jenkins,提示:No valid crumb was included in the request
    python语言的jenkinapi
    Jenkins Pipeline+Maven+Gitlab持续集成构建
    windows中卸载Jenkins
  • 原文地址:https://www.cnblogs.com/yiqiAtiya/p/12184408.html
Copyright © 2011-2022 走看看