莫比乌斯&线性筛

最难受的莫过于正式赛因为平常不训练,训练懒就不写博客导致莫比乌斯忘记怎么做了???菜是原罪,nothing to say。

抢救一波线性筛(有生之年还能用上吗):

const int MAX = 1e6+10;
const ll mod = 1e9+7;
ll mob[MAX],d[MAX],facnum[MAX],sum[MAX],p[MAX],f[MAX];
bool noprime[MAX];
void get_all()  
{  
    int pnum = 0;  
    phi[1] = 1;  //欧拉 
    mob[1] = 1;  //莫比乌斯 
    facnum[1] = 1;  //小于自己的约数个数 
    for(int i = 2; i < MAX; i++)  
    {  
        if(!noprime[i])  
        {  
            phi[i] = i - 1;  
            mob[i] = -1;  
            p[pnum ++] = i;     
            facnum[i] = 2;    
            d[i] = 1;        
        }  
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)  
        {  
            noprime[i * p[j]] = true;  
            if(i % p[j] == 0)  
            {  
                phi[i * p[j]] = phi[i] * p[j];  
                mob[i * p[j]] = 0;  
                facnum[i * p[j]] = facnum[i] / (d[i] + 1) * (d[i] + 2);   
                d[i * p[j]] = d[i] + 1;   
                break;  
            }  
            phi[i * p[j]] = phi[i] * (p[j] - 1);  
            mob[i * p[j]] = -mob[i];  
            facnum[i * p[j]] = facnum[i] * 2;  
            d[i * p[j]] = 1;   
        }  
    }  
}  
以HDU-6134为例,给出常见解题方案:

g(i)=nj=1ij,h(i)=nj=1ij[(i,j)=1] 
那么g(i)=d|ih(d) 
//求解g(i)我是枚举j(2<=j<=N)ij,然后可以知道[(j1)i+1,ji]这段区间是可以一起处理的,因为这段区间除以j后的结果都一样。 
我们只需g((j1)i+1)+=j,g(ji+1)=j,然后前缀和就是要求的g(i)

现在我们已经知道了g(i),要求h(i)。我们可以用莫比乌斯反演。 
可知h(i)=d|iμ(d)g(i/d) 
如果你直接两个for循环枚举ii的因子是会T的。 
这里我们第一个for可以枚举d,然后第二个for枚举i每次加d,可以在O(nlogn)的时间内处理出来(应该是这个复杂度。。) 
然后对h(i)求前缀和就是f(i) 
然后O(1)查询


#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX = 1e6+10;
const ll mod = 1e9+7;
ll mob[MAX],d[MAX],facnum[MAX],sum[MAX],p[MAX],f[MAX];
bool noprime[MAX];
void get_all()
{
    memset(noprime,false,sizeof(noprime));
    int pnum = 0;
    //phi[1] = 1;
    mob[1] = 1;
    sum[1]=1;
    facnum[1] = 1;
    for(int i = 2; i < MAX; i++)
    {
        if(!noprime[i])
        {
            //phi[i] = i - 1;
            mob[i] = -1;
            p[pnum ++] = i;
            facnum[i] = 2;
            d[i] = 1;
        }
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            noprime[i * p[j]] = true;
            if(i % p[j] == 0)
            {
                //phi[i * p[j]] = phi[i] * p[j];
                mob[i * p[j]] = 0;
                facnum[i * p[j]] = facnum[i] / (d[i] + 1) * (d[i] + 2);
                d[i * p[j]] = d[i] + 1;
                break;
            }
            //phi[i * p[j]] = phi[i] * (p[j] - 1);
            mob[i * p[j]] = -mob[i];
            facnum[i * p[j]] = facnum[i] * 2;
            d[i * p[j]] = 1;
        }
    }
    f[1]=1;
    sum[1]=1;
    for(int i=2;i



 

你可能感兴趣的:(莫比乌斯反演)