您的位置:首页 > 其它

【JZOJ 3623】【SDOI2014】数表

2017-03-07 21:16 253 查看

Description



Solution

本题为看到gcd上反演系列,

设fd表示能整除d的自然数总和,

Ans=∑i=1n∑j=1mfgcd(i,j)

反演的套路就不写了,

Ans=∑T=1min(n,m)⌊nT⌋⌊mT⌋∑d|Tfd∗μ(Td)

有因为有f的大小限制,这个只能得部分分,

正解是离线,按f的限制排序,

再把f排序,

设sn=∑d|nμ(nd)fd[fd<=a]

每次限制变大,就会有一些新的f符合要求,

设fi现在变得符合要求,

那么,影响到的s就只有是i的倍数的s,

就是sd=sd+fi(d|i),

这个不停枚举d的过程是O(nlog(n))

有因为要分块,要做s的前缀和,

所以就用树状数组。

复杂度:O(nlog(n)2+Q∗(n−−√+m−−√)∗log(n))

PS:祝君卡常愉快!

分块的时候注意尽量不要用(LL)/(LL),超级慢。

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define min(q,w) ((q)<(w)?(q):(w))
#define NX(q) ((q)&(-(q)))
using namespace std;
typedef long long LL;
const int N=200500;
LL mo=1073741824;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
int f
;
LL Ans
;
bool prz
;
int pr
,mu
;
struct qqww
{
LL v;int n;
}b
;
struct qwqw
{
int n,m,K,i;
}sc
;
int c
,g
;
bool cz
;
LL sum
;
void ss(int I,int q,LL e)
{
f[q]=e;
fo(i,I,pr[0])
{
LL t=1;
LL t1=e;
bool z=1;
while(1)
{
t*=pr[i];
t1=(t1+e*t);
if(t*q>n)break;
if(t1>1e9){printf("swddwdw %lld\n",t*q); break;}
ss(i+1,t*q,t1);
z=0;
}
if(z)break;
}
}
bool PX(qqww q,qqww w){return q.v<w.v;}
bool PXsc(qwqw q,qwqw w){return q.K<w.K;}
void add(int q,LL w){for(;q<=n;q+=NX(q))f[q]+=w;}
LL Gsum(int q)
{
// return 1;
LL ans=0;
for(;q>0;q-=NX(q))ans+=f[q];
return ans;
}
LL fk(int n,int m)
{
int i=1;
LL ans=0;
while(i<=n)
{
LL nx=min(n/(n/i),m/(m/i));
ans=(ans+(LL)(n/i)*((LL)m/i)*(Gsum(nx)-Gsum(i-1)))%mo;
i=nx+1;
}
return ans;
}
int main()
{
freopen("table.in","r",stdin);
freopen("table.out","w",stdout);
int q,w;
mo*=2;
n=1e5+10;
mu[1]=1;
fo(i,2,n)
{
if(!prz[i])pr[++pr[0]]=i,mu[i]=-1;
fo(j,1,pr[0])
{
LL t=pr[j]*i;
if(t>n)break;
prz[t]=1;
if(i%pr[j]==0)break;
mu[t]=-mu[i];
}
}
ss(1,1,1);
f[n+1]=2e9;
fo(i,1,n+1)b[i].v=f[i],b[i].n=i,f[i]=0;
sort(b+1,b+1+n,PX);
int _;
read(_);
fo(i,1,_)
{
read(sc[i].n),read(sc[i].m),read(sc[i].K),sc[i].i=i;
if(sc[i].n>sc[i].m)swap(sc[i].n,sc[i].m);
}
sort(sc+1,sc+1+_,PXsc);
q=1;
fo(i,1,_)
{
while(b[q].v<=sc[i].K)
{
int t=b[q].n,cs=b[q].v;
int jn=n/t;
fo(j,1,jn)if(mu[j])add(j*t,cs*mu[j]);
q++;
}
Ans[sc[i].i]=(fk(sc[i].n,sc[i].m)+mo)%mo;
}
fo(i,1,_)printf("%lld\n",Ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: