• 【BZOJ3309】DZY Loves Math(莫比乌斯反演)


    【BZOJ3309】DZY Loves Math(莫比乌斯反演)

    题面

    [sum_{i=1}^asum_{j=1}^bf(gcd(a,b)) ]

    其中,(f(x))表示(x)分解质因数之后,最高的幂次

    题解

    完全不会莫比乌斯反演了。
    先来推式子

    [sum_{d=1}^asum_{i=1}^{a/d}sum_{j=1}^{b/d}[gcd(i,j)=1]f(d) ]

    [sum_{d=1}^af(d)sum_{i=1}^{a/d}sum_{j=1}^{b/d}[gcd(i,j)=1] ]

    (F(x)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=x])
    (G(x)=sum_{x|d}f(d)=sum_{i=1}^nsum_{j=1}^m[x|gcd(i,j)])
    所以(G(x)=[frac{n}{x}][frac{m}{x}])
    所以原式可以变为
    又有(F(x)=sum_{x|d}mu(frac{d}{x})G(d))
    所以(F(1)=sum_{d=1}^nmu(d)G(d))
    所以所求变为

    [sum_{d=1}^af(d)sum_{i=1}^{a/d}mu(i)G(i) ]

    [sum_{d=1}^af(d)sum_{i=1}^{a/d}mu(i)[frac{a}{id}][frac{b}{id}] ]

    老套路了,令(T=id)

    [sum_{T=1}^a[frac{a}{T}][frac{b}{T}]sum_{d|T}f(d)mu(frac{T}{d}) ]

    后面这个玩意怎么算呢??
    迷茫啊。。。。

    考虑枚举的每一个(T=p1^{a1}*p2^{a2}...pn^{an})
    因为(mu)要非零才有贡献,所以(frac{T}{d})的每一个质因数最多取(1),因此一共有(2^n)个对应的(d)
    假设确定了选择某个质因数(px^{ax-1}),并且它是最高幂了
    那么所有比它低的幂次都可以随意选或者不选,
    一共是(2^{?-1})个,不难证明此时(f(d))的值一样,(mu)的值恰好一一对应为(-1,1),此时的和一定为(0)
    这样的前提是存在比他低的次幂,也就意味着所有的幂次不全相等。

    假设全部相等的时候?
    也就是(T=(p1p2p3..pn)^a)
    (d=(p1p2..pn)^{a-1})时,(f(d)=a-1)
    其他情况下(f(d)=a)
    先假设所有情况下(f(d)=a)
    显然最终的和也是(0)
    但是有一种情况下为(a-1),因此要对于上面那种情况额外把(1)减掉
    因此贡献是(-1*mu(p1p2p3..pn)=(-1)^{(n+1)})

    这样就可以算出后面那一坨东西的值了。
    至于怎么线性筛?
    额外记录每个数出去最小质因子后的数(lst[i])
    以及最小质因子的幂次
    这样就可以通过(lst[i])计算出结果了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 10000000
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    bool zs[MAX+1];
    int pri[MAX+1],tot,g[MAX+1],lst[MAX+1],fp[MAX+1];
    void pre()
    {
    	for(int i=2;i<=MAX;++i)
    	{
    		if(!zs[i])pri[++tot]=i,lst[i]=g[i]=fp[i]=1;
    		for(int j=1;j<=tot&&i*pri[j]<=MAX;++j)
    		{
    			int x=i*pri[j];
    			zs[x]=true;
    			if(i%pri[j]==0)
    			{
    				lst[x]=lst[i];
    				fp[x]=fp[i]+1;
    				if(lst[x]==1)g[x]=1;
    				else g[x]=(fp[lst[x]]==fp[x]?-g[lst[x]]:0);
    				break;
    			}
    			lst[x]=i;fp[x]=1;g[x]=(fp[i]==1?-g[i]:0);
    		}
    	}
    	for(int i=1;i<=MAX;++i)g[i]+=g[i-1];
    }
    int main()
    {
    	pre();
    	int T=read();
    	while(T--)
    	{
    		int a=read(),b=read();
    		if(a>b)swap(a,b);
    		ll ans=0;
    		for(int i=1,j;i<=a;i=j+1)
    		{
    			j=min(a/(a/i),b/(b/i));
    			ans+=1ll*(a/i)*(b/i)*(g[j]-g[i-1]);
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    sql server 中各个系统表的作用==== (转载)
    后台动态设置前台标签内容和属性
    利用C#编写一个简单的抓网页应用程序
    如何创建和使用Web Service代理类
    jdbc如何取得存储过程return返回值
    子窗口和父窗口的函数或对象能否相互访问 (转载)
    把aspx文件编译成DLL文件
    C#中的类型转换
    c#中对文件的操作小结
    转贴一篇 自定义数据库 希望对你有帮助
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8807560.html
Copyright © 2020-2023  润新知