1. 程式人生 > >[BZOJ3529][SDOI2014]數表

[BZOJ3529][SDOI2014]數表

++ swap mes include cnblogs clas ips 位置 mat

BZOJ
Luogu
題意:給定n,m,a,求
\[\sum_{i=1}^{n}\sum_{j=1}^{m}[\sigma(\gcd(i,j))\le{a}]\sigma(\gcd(i,j))\]
多組數據,\(n,m\le10^5\)

sol

首先\(\sigma(i)\)是個積性函數,在積性函數與線性篩中提到了篩的方法,可供參考。
多組數據不好處理,但好在可以離線。把所有詢問按照\(a\)排序,再把1-N所有數按照\(\sigma(i)\)排序,再依次加入。
為了動態維護前綴和就需要寫樹狀數組。
考慮到每個數只會被加入一次,被加入在\(\lfloor\frac Ni\rfloor\)個位置,所以加入的復雜度是\(O(\sum_{i=1}^{n}\lfloor \frac ni\rfloor*\log_2{n})\)


查詢依然是數論分塊,復雜度是\(O(n\sqrt{n}\log_{2}n)\)
tips:取模自然溢出即可

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100005;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-'
) w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } struct query{ int n,m,a,id; bool operator < (const query &zsy) const {return a<zsy.a;} }q[N]; int T,maxN,pri[N],tot,zhi[N],mu[N],low[N],sum[N],sigma[N],id[N],c[N],ans[N]; void
Mobius() { zhi[1]=mu[1]=low[1]=sum[1]=sigma[1]=1; for (int i=2;i<=maxN;i++) { if (!zhi[i]) { low[i]=pri[++tot]=i; mu[i]=-1;sum[i]=sigma[i]=i+1; } for (int j=1;j<=tot&&i*pri[j]<=maxN;j++) { zhi[i*pri[j]]=1; if (i%pri[j]==0) { low[i*pri[j]]=low[i]*pri[j]; sum[i*pri[j]]=sum[i]+low[i*pri[j]]; sigma[i*pri[j]]=sigma[i]/sum[i]*sum[i*pri[j]]; break; } mu[i*pri[j]]=-mu[i]; low[i*pri[j]]=pri[j]; sum[i*pri[j]]=pri[j]+1; sigma[i*pri[j]]=sigma[i]*sigma[pri[j]]; } } } void Modify(int k,int val){for (;k<=maxN;k+=k&-k) c[k]+=val;} int Query(int k){int res=0;for (;k;k-=k&-k) res+=c[k];return res;} bool cmp(int x,int y){return sigma[x]<sigma[y];} int calc(int n,int m) { int i=1,j,pre=0,cur,res=0; while (i<=n) { j=min(n/(n/i),m/(m/i)); cur=Query(j); res+=(n/i)*(m/i)*(cur-pre); i=j+1;pre=cur; } return res; } int main() { T=gi(); for (int i=1;i<=T;i++) { q[i]=(query){gi(),gi(),gi(),i}; if (q[i].n>q[i].m) swap(q[i].n,q[i].m); maxN=max(maxN,q[i].n); } Mobius(); for (int i=1;i<=maxN;i++) id[i]=i; sort(q+1,q+T+1);sort(id+1,id+maxN+1,cmp); for (int i=1,p=1;i<=T;i++) { for (;p<=maxN&&sigma[id[p]]<=q[i].a;p++) for (int j=id[p];j<=maxN;j+=id[p]) Modify(j,sigma[id[p]]*mu[j/id[p]]); ans[q[i].id]=calc(q[i].n,q[i].m); } for (int i=1;i<=T;i++) printf("%d\n",ans[i]<0?ans[i]+2147483647+1:ans[i]); return 0; }

[BZOJ3529][SDOI2014]數表