zoukankan      html  css  js  c++  java
  • 4.10 省选模拟赛 约数 数论 转换 三元组个数

    avatar
    avatar

    题目很简明 可是 上午反演的时候无计可施。

    直接做是nln的 可以简单转换一下 原式=(sum_{x=1}^nfrac{n}{x}d(x))

    这样就有一个O(n)的做法了 由于d是积性函数直接筛就好了。没必要整除分块 直接O(n).

    const int MAXN=15000010;
    int n,top;
    int v[MAXN],g[MAXN],p[1000010],d[MAXN];
    inline void prepare()
    {
    	d[1]=1;
    	rep(2,n,i)
    	{
    		if(!v[i])
    		{
    			p[++top]=g[i]=v[i]=i;
    			ll sum=p[top];int j=1;
    			while(sum<=n)d[sum]=j+1,sum=sum*p[top],++j;
    		}
    		rep(1,top,j)
    		{
    			if(n/i<p[j])break;
    			int ww=i*p[j];
    			v[ww]=p[j];
    			if(p[j]==v[i])
    			{
    				g[ww]=g[i]*p[j];
    				d[ww]=d[i/g[i]]*d[g[ww]];
    				break;
    			}
    			d[ww]=d[i]*d[p[j]];
    			g[ww]=p[j];
    		}
    	}
    }
    int main()
    {
    	//freopen("divisor.in","r",stdin);
    	//freopen("divisor.out","w",stdout);
    	get(n);
    	if(n<=15000000)
    	{
    		prepare();//put(top);
    		//rep(1,n,i)put(d[i]);
    		ll sum=0;
    		rep(1,n,i)sum=sum+(ll)(n/i)*d[i];
    		putl(sum);
    	}
    	return 0;
    }
    

    推到这里就可以自闭了。

    d这个函数的前缀和不能杜教筛 也没有一个gcd的东西可以代替 如(d(i)=sum_{x=1}^{i}[(x,i)=x])这个东西没啥用 还是很难化简。

    还要一个 (d(xy)=sum_{i|x}^{x}sum_{j|y}^{y}[(i,j)=1])

    都跟本题没啥关系。

    这道题之所以能做是因为 求的是前缀和这个特异性问题。

    (d(w)=sum_{x|w}1) 观察这个东西可以发现(x,frac{w}{x})这个东西是一个二元组。

    (sum_{i=1}^nsum_{p|i}d(p))观察这个东西 对于一个i来说 有(frac{i}{p},d(p))(frac{i}{p},frac{w}{x},x)

    这个三元组会对答案贡献1.

    可以发现 对于所有的三元组 xyz<=n 这样的三元组都会被计数。

    且这个三元组是唯一存在于一个数字i内的。

    设x<=y<=z.若x<=(n^{frac{1}{3}},yleq sqrt(frac{n}{x}))

    枚举x,y统计z的数量即可。

    由于x,y,z可以是一个排列所以要乘6.

    但是观察上面的三元组的情况 发现对于x==y的时候这种情况是没有排列的所以需要减掉相应的次数 三个数字相等也同理。

    非常妙的一道题。至于复杂度接近于(n^{frac{2}{3}})(我也不会证明。

    const ll MAXN=100010;
    ll n;
    int main()
    {
    	freopen("divisor.in","r",stdin);
    	freopen("divisor.out","w",stdout);
    	get(n);
    	ll w1=1,w2=1,ans=0;
    	while(w1*w1*w1<=n)++w1;--w1;
    	while(pf(w2)<=n)++w2;--w2;
    	for(ll i=1;i<=w1;++i)
    	{
    		ll ww=n/i;
    		for(ll j=i;j*j<=ww;++j)ans+=ww/j-j+1;
    	}
    	ll cnt=0;
    	for(ll i=1;i<=w2;++i)cnt+=n/i/i;
    	putl(ans*6-cnt*3-2*w1);
    	return 0;
    }
    
  • 相关阅读:
    How to create jar for Android Library Project
    Very large tabs in eclipse panes on Ubuntu
    64bit Ubuntu, Android AAPT, R.java
    Linux(Ubuntu)下如何安装JDK
    Configure xterm Fonts and Colors for Your Eyeball
    建立、配置和使用Activity——启动其他Activity并返回结果
    建立、配置和使用Activity——使用Bundle在Activity之间交换数据
    建立、配置和使用Activity——启动、关闭Activity
    建立、配置和使用Activity——Activity
    异步任务(AsyncTask)
  • 原文地址:https://www.cnblogs.com/chdy/p/12675665.html
Copyright © 2011-2022 走看看