zoukankan      html  css  js  c++  java
  • 莫比乌斯反演套路二--(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+qsqrt 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
    ",ans[c]);
    84     return 0;
    85 }
    View Code
  • 相关阅读:
    基于WEB的仓库管理系统设计与实现
    基于SSH的医院在线挂号系统设计与实现
    Java新闻发布管理系统设计与实现
    基于java记账管理系统设计与实现
    基于java电脑彩票销售管理系统的设计与实现
    基于JAVA的推箱子游戏系统设计与实现
    银行柜员业务绩效考核系统的设计与实现
    医院管理住院系统设计与实现
    陶瓷工厂的进销存管理系统设计与实现
    搜索引擎的设计与实现
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8176859.html
Copyright © 2011-2022 走看看