EOJ 262 润清的烦恼

——题目出处zhoutb2333

题解:

3e6可以带一个log

又是下取整问题。但是分块会TLE。

这样考虑,我们把式子拆成两个部分。

我们先算出来每一个x的[ai/x]项,再算出来[x/ai]项。之后做和。

[x/ai]:

x和ai的倍数有一些关系。

发现,假设现在x|ai,且x/ai=k, 那么,对于任意的(x~x+ai-1)[x/ai]=k;

所以,我们可以反过来,对于每一个ai,枚举ai的倍数,在ai的每个倍数的位置上++,这个桶叫val

那么,一个x,[x/ai]的值,就是val[1~x]的和!即一个前缀和。

所以我们外层循环i,给ai的倍数打标记 。

但是会被卡,ai=1时,复杂度M^2

所以给ai再开一个桶,cnt[i]表示值为i的ai有多少个。

枚举i的倍数即可,每次val+=cnt[i],一次加了许多个。

复杂度:M*(1/1+1/2+1/3+...1/M)= MlogM

另外一部分:

[ai/x]

ai和x的倍数有一些关系。

这次就考虑外层枚举x,思路和上面差不多。

枚举x的每一个倍数j,k=j/x,

那么,对于数值在(k*x,k*x+x-1)的区间内的所有的ai,[ai/x]=k

把刚才那个桶cnt,进行一个前缀和。

所以,对于这个x,每个倍数j的贡献是:(sum(k*x+x-1)-sum(k*x-1))*k

复杂度同上。

然后两边做和就可以了。

注意:脑残的一点:n大于2e5的手动构造,mod M再加1,不是mod(M+1)

显然啊,Ai数值不能是(0,M)的,而是(1,M)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3000000+4;
ll n,m;
ll a[N];
ll cnt[N],tot;
ll val[N];
ll lp[N];
ll s[N];
int main()
{
    scanf("%lld%lld",&n,&m);
    if(n<2e5){
      for(int i=1;i<=n;i++){
          scanf("%d",&a[i]);
          cnt[a[i]]++;
      }
    }
    else{int t;
        scanf("%lld",&a[1]);
        cnt[a[1]]++;
        for(int i=2;i<=n;i++){
            a[i]=(1LL*a[i-1]*a[i-1]+1LL*7*a[i-1]+34221)%m+1;
            cnt[a[i]]++;
        }
    }
    for(int i=1;i<=m;i++){
        s[i]=s[i-1]+cnt[i];
        if(!cnt[i]) continue;
        for(int j=i;j<=m;j+=i){
            val[j]+=cnt[i];
        }
    }
    //for(int i=1;i<=m;i++){
///        cout<<s[i]<<endl;
    //}
    for(int i=1;i<=m;i++){
        for(int j=i;j<=m;j+=i){
            lp[i]+=(s[min((ll)j+i-1,m)]-s[j-1])*(j/i);
        }
    }
    ll ans=0;
    for(int i=1;i<=m;i++){
        val[i]+=val[i-1];
        //cout<<val[i]<<" "<<lp[i]<<endl;
        ans^=(lp[i]+val[i]);
    }
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Miracevin/p/9633093.html