zoukankan      html  css  js  c++  java
  • [bzoj3529][Sdoi2014]数表_树状数组_莫比乌斯反演

    数表 bzoj-3529 Sdoi-2014

    题目大意:n*m的数表,第i行第j列的数是同时整除i和j的所有自然数之和。给定a,求数表中所有不超过a的和。

    注释:$1le n,m le 10^5$。


    想法:我们先不考虑那个a的限制:我们设f(i)表示整除i的自然数之和。

         $sumlimits_{i=1}^nsumlimits_{j=1}^m f(gcd(i,j))$

    $=sumlimits_{i=1}^nsumlimits_{j=1}^m f(d)cdot [gcd(i,j)==d]$

    $=sumlimits_{d=1}^n f(d)sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{m}{d} floor}[gcd(i,j)==1]$

    $=sumlimits_{d=1}^n f(d)sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sumlimits_{e|i,e|j} mu(e)$

    $=sumlimits_{d=1}^n f(d)sumlimits_{e=1}^{lfloorfrac{n}{d} floor}mu(e)sumlimits_{i=1}^{lfloorfrac{n}{de} floor}sumlimits_{j=1}^{lfloorfrac{m}{de} floor}$

    $=sumlimits_{D=1}^n sumlimits_{d|D} f(d)cdot mu(frac{D}{d})sum(lfloorfrac{n}{D} floor)sum(lfloorfrac{m}{D} floor)$

    然后,显然$f$函数是积性函数,$mu$函数是积性函数,所以$f$和$mu$的狄利克雷卷积$fcdot mu$是积性函数,所以不限制的问题就解决了。

    那我们考虑限制怎么办?其实也非常简单。我们只需要在树状数组上维护出小于a的f,查询即可。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define inf 2147483647
    using namespace std;
    typedef long long ll; 
    const int N=100010;
    int mu[N],e[N],ans[N],c[N],vis[N],p[N],t[N],g[N];
    struct F{int d,num;}f[N];
    struct Q{int n,m,a,id;}q[N];
    inline bool cmpT(Q a,Q b){return a.a<b.a;}
    inline bool cmpt(F a,F b){return a.d<b.d;}
    inline int lowbit(int x){return x&-x;}
    int power(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if (b&1) res*=a;
    		a*=a;
    		b>>=1;
    	}
    	return res;
    }
    void add(int x,int val)
    {
    	for(int i=x;i<N;i+=lowbit(i)) c[i]+=val;
    }
    int query(int x)
    {
    	int s=0;
    	for(int i=x;i;i-=lowbit(i)) s+=c[i];
    	return s;
    }
    int main()
    {
    	mu[1]=1;f[1].d=f[1].num=1;
    	for(int i=2;i<N;i++)
    	{
    		f[i].num=i;
    		if(!vis[i]) mu[i]=-1,f[i].d=t[i]=1+i,g[i]=1,p[++p[0]]=i;
    		for(int j=1;j<=p[0] && i*p[j]<N;j++)
    		{
    			vis[i*p[j]]=1;
    			if(i%p[j]==0)
    			{
    				mu[i*p[j]]=0;
    				g[i*p[j]]=g[i]+1;
    				t[i*p[j]]=t[i]+power(p[j],g[i]+1);
    				f[i*p[j]].d=f[i].d/t[i]*t[i*p[j]];
    				break;
    			}
    			else
    			{
    				mu[i*p[j]]=-mu[i];
    				f[i*p[j]].d=f[i].d*f[p[j]].d;
    				g[i*p[j]]=1;t[i*p[j]]=p[j]+1;
    			}
    		}
    	}
    	int T; scanf("%d",&T);
    	for(int i=1;i<=T;i++) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].id=i;
    	sort(q+1,q+1+T,cmpT);
    	sort(f+1,f+N,cmpt);
    	for(int now=0,i=1;i<=T;i++)
    	{
    		while(now+1<N && f[now+1].d<=q[i].a)
    		{
    			now++;
    			for(int j=1;j*f[now].num<N;j++)
    			{
    				add(j*f[now].num,mu[j]*f[now].d);
    			}
    		}
    		int n=q[i].n,m=q[i].m;
    		if(n>m) swap(n,m);
    		for(int j=1,k;j<=n;j=k+1)
    		{
    			k=min(n/(n/j),m/(m/j));
    			ans[q[i].id]+=(n/j)*(m/j)*(query(k)-query(j-1));
    		}
    		ans[q[i].id]&=inf;
    	}
    	for(int i=1;i<=T;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    小结:这就是典型的拟对象的题,我们通过先构造拟对象,然后向完全对象转化,非常巧妙。

  • 相关阅读:
    V4L2 soccamera 子系统
    ubuntu10.04 vim 配置
    Video for Linux Two
    I2C总线的仲裁机制
    Android Camera 通过V4L2与kernel driver的完整交互过程
    ubuntu安装辞典
    v4l2 camera 驱动架构 之 isp controller 驱动
    Android Camera 运行流程
    CentOS 7.x安装图文示范
    同余与模运算
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9380018.html
Copyright © 2011-2022 走看看