P5572 [CmdOI2019]简单的数论题

[CmdOI2019]简单的数论题

题意即求:

i=1nj=1mφ(lcm(i,j)gcd(i,j))(mod23333)

其中 T3×104mn5×104

此题需要按不同值域分类处理,对复杂度的降低类似分块的想法。

首先推导:

i=1nj=1mφ(lcm(i,j)gcd(i,j))=i=1nj=1mφ(igcd(i,j)jgcd(i,j))=i=1nj=1mφ(igcd(i,j))φ(jgcd(i,j))=d=1i=1nj=1m[gcd(i,j)=d]φ(id)φ(jd)=d=1i=1n/dj=1m/dφ(i)φ(j)[gcd(i,j)=1]=d=1i=1n/dj=1m/dφ(i)φ(j)ki,kjμ(k)=d=1k=1μ(k)i=1n/kdj=1m/kdφ(ik)φ(jk)=T=1dTμ(d)i=1n/Tφ(id)j=1m/Tφ(jd)

看上去就非常恐怖。

先定义 F(x,d)=i=1xφ(id)

注意到有 xdn,那么 F(x,d) 的数量是在 O(nlnn) 的。我们可以开一个 vector 解决掉。处理这部分的复杂度也是 O(nlnn) 的。

接下来处理中间这个大头。

我们定义:

G(x,y,z)=T=1zdTμ(d)F(x,d)F(y,d)

看起来很奇怪,但是我们可以有:

T=1dTμ(d)i=1n/Tφ(id)j=1m/Tφ(jd)=l,rG(n/l,m/l,r)G(n/l,m/l,l1)

这里 [l,r] 代表在数论分块中 n/l=n/r 的一个块。

但是这并没有优化复杂度。

考虑一个数量级 B

对于 x,yBG(x,y,z),我们预先处理,时间复杂度是 O(nB2lnn) 的。

那这样 n/lB 的所有 l 我们都能处理,在查询下的总复杂度就是 O(Tn) 的。

那对于 n/l>B 的所有 l,我们知道会有 l<n/B,那么这一部分我们直接暴力处理也可以,查询下的总时间复杂度就是 O(T(n/B)lnn) 的。

最后总的时间复杂度就是 O(nB2lnn+T(n/B)lnn+Tn)

采用根号平衡,算出 B=T3。(这里取的是 B=50

最后得到时间复杂度 O(T2/3nlnn+Tn)

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#define ll int
using namespace std;
namespace Ehnaev{
  inline ll read() {
    ll ret=0,f=1;char ch=getchar();
    while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
    while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
    return ret*f;
  }
  inline void write(ll x) {
    static char buf[22];static ll len=-1;
    if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
    else {putchar(10);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
    while(len>=0) putchar(buf[len--]);
  }
}using Ehnaev::read;using Ehnaev::write;
inline void writeln(ll x) {write(x);putchar(10);}

const ll mo=23333,N=5e4,B=50;

ll T,n,m,ans,cnt;
ll prime[N+5],mu[N+5],phi[N+5];
vector<ll> f[N+5];
ll g[B+5][B+5][N+5];
bool ff[N+5];

inline void Init() {
  ff[1]=1;mu[1]=1;phi[1]=1;
  for(ll i=2;i<=N;i++) {
    if(!ff[i]) {prime[++cnt]=i;mu[i]=mo-1;phi[i]=(i-1)%mo;}
    for(ll j=1;j<=cnt&&i*prime[j]<=N;j++) {
      ff[i*prime[j]]=1;
      if(i%prime[j]==0) {
        mu[i*prime[j]]=0;
        phi[i*prime[j]]=phi[i]*prime[j]%mo;
        break;
      }
      mu[i*prime[j]]=mu[i]*mu[prime[j]]%mo;
      phi[i*prime[j]]=phi[i]*phi[prime[j]]%mo;
    }
  }
  for(ll i=0;i<=N;i++) f[0].push_back(0);
  for(ll i=1;i<=N;i++) f[i].push_back(0);
  for(ll i=1;i<=N;i++) {
    for(ll j=i,cn=1;j<=N;j+=i,cn++) {
      f[cn].push_back((f[cn-1][i]+phi[j])%mo);
    }
  }
  for(ll i=1;i<=B;i++) {
    for(ll j=1;j<=B;j++) {
      for(ll k=1;k*i<=N&&k*j<=N;k++) {
        ll tmp=(mu[k]*f[i][k]%mo)*f[j][k]%mo;
        for(ll l=k;l*i<=N&&l*j<=N;l+=k) {
          g[i][j][l]=(g[i][j][l]+tmp)%mo;
        }
      }
    }
  }
  for(ll i=1;i<=B;i++) {
    for(ll j=1;j<=B;j++) {
      for(ll k=1;k*i<=N&&k*j<=N;k++) {
        g[i][j][k]=(g[i][j][k-1]+g[i][j][k])%mo;
      }
    }
  }
  // for(ll i=1;i<=3;i++) {
  //   for(ll j=1;j<=3;j++) {
  //     for(ll k=1;k<=3;k++) {
  //       printf("g[%d][%d][%d]=%d\n",i,j,k,g[i][j][k]);
  //     }
  //   }
  // }
}

int main() {

  T=read();Init();

  while(T--) {
    n=read();m=read();ans=0;
    for(ll i=1;i*B<=n;i++) {
      for(ll j=i;j*B<=n;j+=i) {
        ll tmp=(mu[i]*f[n/j][i]%mo)*f[m/j][i]%mo;
        ans=(ans+tmp)%mo;
      }
    }
    for(ll i=n/B+1,j;i<=m;i=j+1) {
      j=min(n/(n/i),m/(m/i));
      ll tmp=(g[n/i][m/i][j]-g[n/i][m/i][i-1]+mo)%mo;
      ans=(ans+tmp)%mo;
    }
    writeln(ans);
  }

  return 0;
}
posted @   Aryper  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示