3529: [Sdoi2014]数表 莫比乌斯反演+树状数组

来源:互联网 发布:mac inode没有en4 编辑:程序博客网 时间:2024/05/22 17:13

Dragonite神犇的题。。不知道省选现场怎么样。。


我们定义F(i)i的约束和,题目要求的是

i=1nj=1mF(gcd(i,j)) mod 231,F(gcd(i,j))<=a

我们先忽略a这个限制,令g(i)表示1xn,1ym,且gcd(x,y)=i的数对(x,y)个数。
那么由莫比乌斯反演,可以得到g(i)=id,dnμ(di)ndmd
然后就有
Ans=i=1nF(i)g(i)

=i=1nF(i)id,dnμ(di)ndmd

=d=1nndmdidF(i)μ(di)

我们令f(i)=idF(i)μ(di),首先线性筛或者枚举每个数更新倍数来预处理出F(i),然后枚举每个数更新倍数,求出f(i)的前缀和,分块就好了。
考虑有了a的限制,我们发现只有F(i)<=ai才对答案有贡献,我们离线处理,按a排序,每次把合法的加入树状数组,然后可以维护出f(i)的前缀和,分块就好辣。
第一次写自然溢出,最后要and 2311

#include<iostream>#include<cstdio>#include<algorithm>#define lowbit(i) (i&(-i))using namespace std;int N;struct query {int n,m,a,id;} q[40005];bool flag[100005];int prime[100005],min_factor_a[100005],min_factor_sum[100005],mobius[100005],tree[100005],ans[40005];pair<int,int> F[100005];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline bool operator<(query a,query b){    return a.a<b.a;}inline void add(int x,int val){    for (int i=x;i<=N;i+=lowbit(i)) tree[i]+=val;}inline int query(int x){    int tmp=0;    for (int i=x;i;i-=lowbit(i)) tmp+=tree[i];    return tmp;}inline void prepare(){    mobius[1]=F[1].first=F[1].second=1;    for (int i=2;i<=N;i++)    {        if (!flag[i])         {            prime[++prime[0]]=i;            mobius[i]=-1;            min_factor_a[i]=i;            min_factor_sum[i]=i+1;            F[i].first=i+1;        }        for (int j=1;j<=prime[0]&&i*prime[j]<=N;j++)        {            flag[i*prime[j]]=1;            if (i%prime[j]==0)             {                mobius[i*prime[j]]=0;                 min_factor_a[prime[j]*i]=min_factor_a[i]*prime[j];                F[i*prime[j]].first=F[i].first/min_factor_sum[i]*(min_factor_sum[i]+min_factor_a[i*prime[j]]);                 min_factor_sum[prime[j]*i]=min_factor_sum[i]+min_factor_a[i*prime[j]];                break;            }            mobius[i*prime[j]]=-mobius[i];            F[i*prime[j]].first=F[i].first*(prime[j]+1);            min_factor_a[i*prime[j]]=prime[j];            min_factor_sum[i*prime[j]]=(prime[j]+1);        }    }    for (int i=1;i<=N;i++) F[i].second=i;}inline void solve(int x){    for (int i=1,pos;i<=q[x].n;i=pos+1)    {        pos=min(q[x].n/(q[x].n/i),q[x].m/(q[x].m/i));        ans[q[x].id]+=(q[x].n/i)*(q[x].m/i)*(query(pos)-query(i-1));    }}int main(){    int testcase=read();    for (int i=1;i<=testcase;i++)    {        q[i].n=read(),q[i].m=read(),q[i].a=read(),q[i].id=i;        if (q[i].n>q[i].m) swap(q[i].n,q[i].m);        N=max(N,q[i].n);    }    prepare();    sort(q+1,q+testcase+1);    sort(F+1,F+N+1);    int now=0;    for (int i=1;i<=testcase;i++)    {        while (now<N&&F[now+1].first<=q[i].a)            for (int j=F[++now].second;j<=N;j+=F[now].second)                add(j,F[now].first*mobius[j/F[now].second]);        solve(i);    }    for (int i=1;i<=testcase;i++)        printf("%d\n",ans[i]&0x7fffffff);    return 0;}
0 0
原创粉丝点击