BZOJ 3529 [Sdoi2014]数表

题目链接

https://lydsy.com/JudgeOnline/problem.php?id=3529

题解

题目要求
∑ i = 1 n ∑ j = 1 m σ 0 ( gcd ⁡ ( i , j ) ) [ σ 0 ( gcd ⁡ ( i , j ) ) ≤ a ] \sum_{i=1}^n\sum_{j=1}^m \sigma_0(\gcd(i,j))[\sigma_0(\gcd(i,j))\leq a] i=1nj=1mσ0(gcd(i,j))[σ0(gcd(i,j))a]
稍微转化一下就是
∑ T = 1 min ⁡ ⌊ n T ⌋ ⌊ m T ⌋ ∑ k ∣ T μ ( T k ) σ 0 ( k ) [ σ 0 ( k ) ≤ a ] \sum_{T=1}^{\min} \lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{k|T}\mu(\frac{T}{k})\sigma_0(k)[\sigma_0(k)\leq a] T=1minTnTmkTμ(kT)σ0(k)[σ0(k)a]

f ( T ) = ∑ k ∣ T μ ( T k ) σ 0 ( k ) [ σ 0 ( k ) ≤ a ] f(T)=\sum_{k|T}\mu(\frac{T}{k})\sigma_0(k)[\sigma_0(k)\leq a] f(T)=kTμ(kT)σ0(k)[σ0(k)a]
考虑对于每一个 σ 0 ( k ) = a \sigma_0(k)=a σ0(k)=a,更新其在对应位置上的 f f f,可以预处理出 σ 0 \sigma_0 σ0,然后以权值为关键字sort一边,离线处理询问,将询问以 a a a为关键字sort一遍,用树状数组维护每个位置的 f f f

这里有一个小技巧,由于对 2 31 2^{31} 231取模,因此可以利用自然溢出,用unsigned来记录答案,最后取模即可。

时间复杂度 O ( T n log ⁡ n + n log ⁡ 2 n ) O(T\sqrt{n}\log n+n\log^2 n) O(Tn logn+nlog2n)

代码

#include <cstdio>
#include <algorithm>
 
int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}
 
const int maxn=100000;
const int maxq=20000;
const unsigned mod=1<<31;
 
namespace bit
{
  unsigned val[maxn+10];
 
  int lowbit(int x)
  {
    return x&(-x);
  }
 
  int add(int pos,unsigned v)
  {
    while(pos<=maxn)
      {
        val[pos]+=v;
        pos+=lowbit(pos);
      }
    return 0;
  }
 
  unsigned getsum(int pos)
  {
    unsigned res=0;
    while(pos)
      {
        res+=val[pos];
        pos-=lowbit(pos);
      }
    return res;
  }
}
 
struct data
{
  int id;
  unsigned val;
 
  bool operator <(const data &other) const
  {
    return val<other.val;
  }
};
 
int p[maxn+10],prime[maxn+10],cnt,low[maxn+10],num[maxn+10];
unsigned mu[maxn+10];
data d[maxn+10];
 
unsigned F(int x,int y)
{
  unsigned res=1;
  for(int i=1; i<=y+1; ++i)
    {
      res*=x;
    }
  return (res-1)/(x-1);
}
 
int getprime()
{
  for(int i=1; i<=maxn; ++i)
    {
      d[i].id=i;
    }
  p[1]=mu[1]=num[1]=d[1].val=1;
  low[1]=0;
  for(int i=2; i<=maxn; ++i)
    {
      if(!p[i])
        {
          prime[++cnt]=i;
          low[i]=num[i]=1;
          mu[i]=-1;
          d[i].val=i+1;
        }
      for(int j=1; (j<=cnt)&&(i*prime[j]<=maxn); ++j)
        {
          int x=i*prime[j];
          p[x]=1;
          if(i%prime[j]==0)
            {
              low[x]=low[i]+1;
              num[x]=num[i];
              mu[x]=0;
              d[x].val=d[num[x]].val*F(prime[j],low[x]);
              break;
            }
          low[x]=1;
          num[x]=i;
          mu[x]=-mu[i];
          d[x].val=d[i].val*(prime[j]+1);
        }
    }
  std::sort(d+1,d+maxn+1);
  return 0;
}
 
struct query
{
  int n,m,v,id;
 
  bool operator <(const query &other) const
  {
    return v<other.v;
  }
};
 
int T;
query q[maxq+10];
unsigned ans[maxn+10];
 
int main()
{
  getprime();
  T=read();
  for(int i=1; i<=T; ++i)
    {
      q[i].n=read();
      q[i].m=read();
      q[i].v=read();
      q[i].id=i;
    }
  std::sort(q+1,q+T+1);
  for(int i=1,j=1; i<=T; ++i)
    {
      while((j<=maxn)&&(d[j].val<=(unsigned)q[i].v))
        {
          for(int k=1; k<=maxn/d[j].id; ++k)
            {
              bit::add(d[j].id*k,mu[k]*d[j].val);
            }
          ++j;
        }
      for(int l=1,r; l<=std::min(q[i].n,q[i].m); l=r+1)
        {
          r=std::min(q[i].n/(q[i].n/l),q[i].m/(q[i].m/l));
          ans[q[i].id]+=(bit::getsum(r)-bit::getsum(l-1))*(q[i].n/l)*(q[i].m/l);
        }
    }
  for(int i=1; i<=T; ++i)
    {
      printf("%u\n",ans[i]&(mod-1));
    }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值