zoukankan      html  css  js  c++  java
  • Codeforces 915 G Coprime Arrays

    Discipntion

    Let's call an array a of size n coprime iff gcd(a1, a2, ..., an) = 1, where gcd is the greatest common divisor of the arguments.

    You are given two numbers n and k. For each i (1 ≤ i ≤ k) you have to determine the number of coprime arrays a of size n such that for every j (1 ≤ j ≤ n1 ≤ aj ≤ i. Since the answers can be very large, you have to calculate them modulo 109 + 7.

    Input

    The first line contains two integers n and k (1 ≤ n, k ≤ 2·106) — the size of the desired arrays and the maximum upper bound on elements, respectively.

    Output

    Since printing 2·106 numbers may take a lot of time, you have to output the answer in such a way:

    Let bi be the number of coprime arrays with elements in range [1, i], taken modulo 109 + 7. You have to print , taken modulo 109 + 7. Here  denotes bitwise xor operation (^ in C++ or Java, xor in Pascal).

    Example

    Input
    3 4
    Output
    82
    Input
    2000000 8
    Output
    339310063

    Note

    Explanation of the example:

    Since the number of coprime arrays is large, we will list the arrays that are non-coprime, but contain only elements in range [1, i]:

    For i = 1, the only array is coprime. b1 = 1.

    For i = 2, array [2, 2, 2] is not coprime. b2 = 7.

    For i = 3, arrays [2, 2, 2] and [3, 3, 3] are not coprime. b3 = 25.

    For i = 4, arrays [2, 2, 2], [3, 3, 3], [2, 2, 4], [2, 4, 2], [2, 4, 4], [4, 2, 2], [4, 2, 4], [4, 4, 2] and [4, 4, 4] are not coprime. b4 = 55.

    一开始没有想到题目求b的整体性,,,直接用了一个简单的容斥,,,然后就T了。。

    如下

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define ll long long 
    #define ha 1000000007
    #define maxn 2000005
    using namespace std;
    int ans[maxn],n,k,tot;
    
    inline int ksm(int x,int y){
    	int an=1;
    	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
    	return an;
    }
    
    inline void get(int x){
    	ans[x]=-ksm(x,n);
    	for(int i=2,j,now;i<=x;i=j+1){
    		now=x/i,j=x/now;
    		ans[x]=((ll)ans[x]+(ll)(j-i+1)*(ll)ans[now])%ha;
    	}
    	
    	ans[x]=-ans[x];
    	if(ans[x]<0) ans[x]+=ha;
    }
    
    int main(){
    	scanf("%d%d",&n,&k);
    	ans[1]=1;
    	for(int i=2;i<=k;i++) get(i);
    	
    	tot=0;
    	for(int i=1;i<=k;i++){
    		tot+=ans[i]^i;
    		while(tot>=ha) tot-=ha;
    	}
    	
    	printf("%d
    ",tot);
    	return 0;
    }
    

      

    后来发现还是要上反演才能过啊hhhh。

    当我们求b[t]的时候:

    设g(x)为gcd是x的倍数的数组个数,
    显然g(x)=(t/x)^n;
    设f(x)为gcd==x的数组个数,
    显然g(x)=Σf(x*i)
    所以=> f(x)=Σg(x*i)*μ(i)

    我们求的显然是f(1),
    所以b[t]=Σg(i)*μ(i)=Σ μ(i) * (t/i)^n

    我们考虑通过b[t-1]推b[t],发现只有i是t的约数时(t/i)变化了,且都是+1;而对于其他的i,(t/i)不变。

    所以我们可以先预处理出b[]的差分(可以做到调和级数的N ln N,通过枚举i,但前提是你得先预处理出(1-k)的n次方最好再把次方的差分也一起算出来)。

    最后求差分的前缀和就是b[]了。

    正解如下

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define ll long long 
    #define ha 1000000007
    #define maxn 2000005
    using namespace std;
    int ans[maxn],n,k,tot;
    int ci[maxn],u[maxn];
    int zs[1000000],t=0;
    bool v[maxn];
    
    inline void init(){
    	u[1]=1;
    	for(int i=2;i<=2000000;i++){
    		if(!v[i]) zs[++t]=i,u[i]=-1;
    		for(int j=1,w;j<=t&&(w=zs[j]*i)<=2000000;j++){
    			v[w]=1;
    			if(!(i%zs[j])) break;
    			u[w]=-u[i];
    		}
    	}
    }
    
    inline int ksm(int x,int y){
    	int an=1;
    	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
    	return an;
    }
    
    int main(){
    	init();
    	
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;i++) ci[i]=ksm(i,n);
    	for(int i=k;i;i--){
    		ci[i]-=ci[i-1];
    		if(ci[i]<0) ci[i]+=ha;
    	}
    	
    	for(int i=1;i<=k;i++)
    	    for(int j=i;j<=k;j+=i){
    	    	ans[j]+=u[i]*ci[j/i];
    	    	if(ans[j]<0) ans[j]+=ha;
    	    	else if(ans[j]>=ha) ans[j]-=ha;
    		}
    	
    	for(int i=1;i<=k;i++){
    		ans[i]+=ans[i-1];
    		if(ans[i]>=ha) ans[i]-=ha;
    		
    		tot+=ans[i]^i;
    		while(tot>=ha) tot-=ha; 
    	}
    	
    	printf("%d
    ",tot);
    	return 0;
    }
    

      

  • 相关阅读:
    R语言:提取路径中的文件名字符串(basename函数)
    课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 0、学习目标
    numpy.squeeze()的用法
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 4、Logistic Regression with a Neural Network mindset
    Python numpy 中 keepdims 的含义
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 3、Python Basics with numpy (optional)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 0、学习目标
    课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 0、学习目标
    windows系统numpy的下载与安装教程
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8421328.html
Copyright © 2011-2022 走看看