zoukankan      html  css  js  c++  java
  • [国家集训队]和与积

    题目

    van了,不会反演了,之后复习了一下午反演终于会做了

    这个东西一看就很神的样子

    [sum_{i=1}^nsum_{j=i+1}^n[{(i+j)}|i imes j] ]

    先分析一下,这个({(i+j)}|i imes j)有什么含义吧

    首先这是一道数学题,那么就极有可能需要往(gcd)上靠,于是我们设(d=(i,j),i=k_1d,j=k_2d)

    显然存在(k_1perp k_2,k_1<k_2)

    那么如果满足({(i+j)}|i imes j)的话,就会有((k_1+k_2)d|k_1k_2d^2),也就是((k_1+k_2)|k_1k_2d)

    我们需要使用一个结论,对于(k_1perp k_2),就会存在((k_1+k_2,k_1k_2)=1)

    这个结论非常好证,首先根据更相减损,((k_1+k_2,k_1)=(k_1+k_2,k_2)=1),既然(k_1+k_2)(k_1)以及(k_2)都互质,那么显然也和(k_1k_2)互质

    于是我们现在就把条件写成了((k_1+k_2)|d)

    这样有什么用呢,考虑(i)(j)都增加(k)倍,这个时候(k_1,k_2)不变,(d)变成了(kd),这个时候((k_1+k_2)|kd)仍然是成立的

    这启示我们枚举(k_1,k_2),之后让(d=k_1+k_2),这样我们就可以一直让(d)加倍来统计答案了

    于是我们得到了这样一个柿子

    [sum_{i=1}^nsum_{j=i+1}^{n}[iperp j]left lfloor frac{n}{j(i+j)} ight floor ]

    后面那个奇奇怪怪的东西是这样的,(i+j)就是(d),这样(jd)就是一个数对中较大的那个数,这个(left lfloor frac{n}{j(i+j)} ight floor)就表示(jd)的倍数在(n)中出现的次数

    对于这个柿子我们直接把(iperp j)写成(sum_{d|i,d|j}mu(d))就好了

    稍微交换一下求和符号,就能写成

    [sum_{d=1}^nmu(d)sum_{i=1}^{left lfloor frac{n}{d} ight floor}sum_{j=i+1}^{2i-1}left lfloor frac{left lfloor frac{n}{id^2} ight floor}{j} ight floor ]

    我们注意到为了让后面的(left lfloor frac{n}{id^2} ight floor>0)(dleq sqrt{n},ileq left lfloor frac{sqrt{n}}{d} ight floor),这样我们暴力枚举(d,i),后面整除分块就好了

    代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define re register
    #define min std::min
    #define LL long long
    const int maxn=5e4+5;
    int n,m;LL ans;
    int mu[maxn],f[maxn],p[maxn>>1];
    inline LL calc(int n,int L,int R) {
    	LL cnt=0;
    	for(int l=L,r; l<=R; l=r+1) {
    		if(!(n/l)) break;
    		r=n/(n/l);r=min(r,R);
    		cnt+=(n/l)*(r-l+1);
    	}
    	return cnt;
    }
    int main() {
    	scanf("%d",&n);
    	m=ceil(std::sqrt(n));f[1]=mu[1]=1;
    	for(re int i=2; i<=m; i++) {
    		if(!f[i]) p[++p[0]]=i,mu[i]=-1;
    		for(re int j=1; j<=p[0]&&i*p[j]<=m; j++) {
    			f[p[j]*i]=1;if(i%p[j]==0) break;mu[p[j]*i]=-mu[i];
    		}
    	}
    	for(re int d=1; d<=m; d++) {
    		if(!mu[d]) continue;
    		for(re int i=1; i*d<=m; i++) {
    			int t=n/i/d/d;
    			if(!t) continue;
    			ans+=mu[d]*calc(t,i+1,2*i-1);
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    杂谈
    分享一首歌——美丽的万物
    Silverlight有感
    风云的银光志Silverlight4.0教程之打印报表和图形(转)
    IIS 7.0的集成模式和经典模式
    WPF中MVVM模式原理分析与实践(转)
    使用HTTP_X_FORWARDED_FOR获取客户端IP的严重后果
    各大网站架构总结笔记(转)
    做了几天silverlight 小结一下
    Fiddler2介绍
  • 原文地址:https://www.cnblogs.com/asuldb/p/11061562.html
Copyright © 2011-2022 走看看