莫比乌斯反演套路二--(n/d)(m/d)给提出来--BZOJ3529: [Sdoi2014]数表

一个数表上第i行第j列表示能同时整除i和j的自然数,Q<=2e4个询问,每次问表上1<=x<=n,1<=y<=m区域内所有<=a的数之和。n,m<=1e5,a<=1e9。对2^31取模。

这个a很讨厌就先不理他。首先i行j列的那个数其实是$a_{ij}=\sum_{x|gcd(i,j)} x$,令$s(t)=\sum_{x|t}x$,然后gcd(i,j)是只有1e5的,可以先把s数组预处理出来。s是积性函数所以线性筛可以搞,但复杂度不在这里,直接埃筛也行。

那现在就是看[1,min(n,m)]中每个数作为gcd的s(t)被算了多少次,也就是1<=x<=n,1<=y<=m中有多少(x,y)=t,记这次数叫f(t),那f(t)是经典的可以反演的式子,反演就不写了,最后$f(t)=\sum_{t|d}\mu(\frac{d}{t})\frac{n}{d}\frac{m}{d}$,最后要求的就是$\sum_{t=1}^{min(n,m)}s(t)\sum_{t|d}\mu(\frac{d}{t})\frac{n}{d}\frac{m}{d}$。

然后我就卡住了。这里用个套路二把后面那俩提出来,变成:$\sum_{d=1}^{min(n,m)}\frac{n}{d}\frac{m}{d}\sum_{t|d}s(t)\mu(\frac{d}{t})$,漂亮,后面那东西(记h(d))预处理一下即可,然后就\sqrt n出解。

然而有了a的限制之后,后面那东西就变得飘忽不定了,这时候需要离线,然后所有s(t)排个序,每次询问前把<=当前a的所有s(t)加给对应的h(d),然后查区间和用树状数组即可。这样就可以在$nlog^2 n+q\sqrt n logn$出解了。

然而排序时忘了cmp函数了。 然而过程中忘了取模导致爆longlong了。 然而没考虑到有负数。 然而树状数组忘开longlong了。

然而最后跑得贼慢,其实对2^31取模只需要int自然溢出最后&2147483647即可。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 //#include<bitset>
 6 #include<algorithm>
 7 //#include<cmath>
 8 using namespace std;
 9 
10 int T,n,m,A;
11 #define maxn 100011
12 int miu[maxn],s[maxn],prime[maxn],lp,us[maxn]; bool notprime[maxn];
13 int snum[maxn];
14 bool cmp(const int &a,const int &b) {return s[a]<s[b];}
15 void pre(int n)
16 {
17     for (int i=1;i<=n;i++)
18         for (int j=i;j<=n;j+=i)
19             s[j]+=i;
20     for (int i=1;i<=n;i++) snum[i]=i;
21     sort(snum+1,snum+1+n,cmp);
22     miu[1]=1; lp=0;
23     for (int i=2;i<=n;i++)
24     {
25         if (!notprime[i]) {prime[++lp]=i; miu[i]=-1;}
26         for (int j=1;j<=lp && 1ll*prime[j]*i<=n;j++)
27         {
28             notprime[i*prime[j]]=1;
29             if (i%prime[j]) miu[i*prime[j]]=-miu[i];
30             else {miu[i*prime[j]]=0; break;}
31         }
32     }
33     for (int i=1;i<=n;i++)
34         for (int j=i,cnt=1;j<=n;j+=i,cnt++)
35             us[j]+=miu[cnt]*s[i];
36 }
37 
38 
39 #define LL long long
40 struct BIT
41 {
42     LL a[maxn],n;
43     BIT() {n=100001;}
44     void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;}
45     LL query(int x) {LL ans=0; for (;x;x-=x&-x) ans+=a[x]; return ans;}
46 }t;
47 
48 struct Q
49 {
50     int n,m,a,id;
51     bool operator < (const Q &b) const {return a<b.a;}
52 }q[maxn];
53 LL ans[maxn];
54 
55 const int base=100001;
56 int main()
57 {
58     pre(base);
59     scanf("%d",&T);
60     for (int i=1;i<=T;i++) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].id=i;
61     sort(q+1,q+1+T);
62     
63     int j=1;
64     const LL tmp=1ll<<31;
65     for (int c=1;c<=T;c++)
66     {
67         while (j<=base && s[snum[j]]<=q[c].a)
68         {
69             for (int k=snum[j],cnt=1;k<=base;k+=snum[j],cnt++)
70                 t.add(k,s[snum[j]]*miu[cnt]);
71             j++;
72         }
73         LL Ans=0;
74         for (int i=1,to=min(q[c].n,q[c].m),last;i<=to;i=last+1)
75         {
76             last=min(q[c].n/(q[c].n/i),q[c].m/(q[c].m/i));
77             Ans+=1ll*(q[c].n/i)*(q[c].m/i)*(t.query(last)-t.query(i-1))%tmp,
78             Ans-=Ans>=tmp?tmp:0,Ans+=Ans<0?tmp:0;
79         }
80         ans[q[c].id]=Ans;
81     }
82     
83     for (int c=1;c<=T;c++) printf("%lld\n",ans[c]);
84     return 0;
85 }
View Code

 

posted @ 2018-01-02 13:44  Blue233333  阅读(356)  评论(0编辑  收藏  举报