[bzoj3529][Sdoi2014]数表
来自FallDream的博客,未经允许,请勿转载,谢谢。
有一张N×m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。
T<=20000组数据,n,m<=10^5
保证n<=m,f(x)表示x的因数和;
枚举gcd $$Ans=\sum_{d=1}^{n}f(d)*\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{d|i,d|j}\mu(d)$$
把d扔出来$$Ans=\sum_{d=1}^{n}f(d)*\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)*\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor$$
令$T=kd$得到$$Ans=\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T,f(d)\leqslant a}f(d)\mu(T/d)$$
前面那坨东西只有根号种取值,但是后面那东西不好计算,考虑把询问按照a排序之后插入树状数组计算答案。
复杂度$O(T\sqrt{n}logn)$
瞎写自然溢出调了半天 最后弃疗了不如取模
#include<iostream> #include<cstdio> #include<algorithm> #define MN 100000 #define ll long long #define mod 2147483647 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int mu[MN+5],s[MN],m,num=0,Ans[MN+5]; bool b[MN+5]; ll ans=0,c[MN+5],sum; pair<ll,int> f[MN+5]; struct ques{ int n,m,a,id; bool operator<(const ques&b)const{return a<b.a;} }q[MN+5]; inline void ins(int x,ll ad){for(;x<=MN;x+=x&(-x)) c[x]+=ad;} inline ll query(int x) { for(sum=0;x;x-=x&(-x)) sum+=c[x]; return sum; } void solve(int a) { for(int j=f[a].second;j<=MN;j+=f[a].second) ins(j,f[a].first*mu[j/f[a].second]); } int main() { mu[1]=1; for(int i=1;i<=MN;i++) for(int j=i;j<=MN;j+=i) f[j].first+=i; for(int i=1;i<=MN;i++) f[i].second=i; for(int i=2;i<=MN;i++) { if(!b[i]) s[++num]=i,mu[i]=-1; for(int j=1;s[j]*i<=MN;j++) { b[s[j]*i]=1; if(i%s[j]==0)break; mu[s[j]*i]=-mu[i]; } } sort(f+1,f+MN+1); m=read(); for(int i=1;i<=m;i++) { q[i].n=read(),q[i].m=read(); if(q[i].n>q[i].m) swap(q[i].n,q[i].m); q[i].a=read();q[i].id=i; } sort(q+1,q+m+1); for(int i=1,j=1;i<=m;i++) { for(;f[j].first<=(ll)q[i].a&&j<=MN;++j) solve(j);ans=0; for(int j=1,last;j<=q[i].n;j=last+1) { last=min(q[i].m/(q[i].m/j),q[i].n/(q[i].n/j)); ans+=((1LL*(query(last)-query(j-1))*(q[i].n/j))&mod)*(q[i].m/j); ans&=mod; } Ans[q[i].id]=ans; } for(int i=1;i<=m;i++) printf("%d\n",Ans[i]); return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream