牛客练习赛29 F 算式子

链接F 算式子

  • 给定\(n\)个整数\(a_i\)。保证\(1\leq a_i\leq m\)
    对于每个\(1\leq x\leq m\),求出\[\sum_{i=1}^{n}([\frac {a_i}{x}]+[\frac {x}{a_i}])\]
  • 不会打向下取整……那两个中括号是向下取整。
  • 还比较好的题,这两个东西可以分开求。
  • 先考虑前面那个,就是考虑对于一个\(x\),考虑\(k*x\)\(k*x+k-1\)中间的\(a_i\)有多少。
  • 然后这一些\(a_i\)都可以产生\(k\)的贡献,前缀和统计就好了。
  • 后面考虑的是对于每一个\(a_i\),他能产生增量贡献的\(x\)有哪一些。
  • 也就是说,对于一个\(a_i\),在\(k*a_i\)处,都会相比之前增加\(1\)的贡献。
  • 所以也是差分后前缀和统计就好了。
  • 注意第一个式子,如果对于任意\(w_i=1\)的情况都直接做的话,复杂度就不是调和级数了。
  • 所以要把相等的数都缩起来,枚举值域。
  • 复杂度\(O(mlogm)\)
#include<bits/stdc++.h>
#define R register int
#define ll long long
#define db double
using namespace std;
const int N=3000001;
int n,m,w[N];
ll G[N],P[N],T[N],ans;
int gi(){
    R x=0,k=1;char c=getchar();
    while((c<'0'||c>'9')&&c!='-')c=getchar();
    if(c=='-')k=-1,c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*k;
}
int main(){
    n=gi(),m=gi();
    for(R i=1;i<=n;++i)w[i]=gi(),G[w[i]]++;
    sort(w+1,w+n+1);
    for(R i=1;i<=m;++i)
        if(G[i])
            for(R j=i;j<=m;j+=i)
                T[j]+=G[i];
    for(R i=1;i<=m;++i)T[i]+=T[i-1],G[i]+=G[i-1];
    for(R i=1;i<=m;++i){
        for(R k=i;k<=m;k+=i)
            P[i]+=(G[min(m,k+i-1)]-G[k-1])*(k/i);
    }
    for(R i=1;i<=m;++i)ans^=(P[i]+T[i]);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Tyher/p/9863465.html