码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj千题计划205:bzoj3529: [Sdoi2014]数表

时间:2018-01-08 13:32:20      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:namespace   约数   分享图片   last   bubuko   bool   不用   geo   log   

http://www.lydsy.com/JudgeOnline/problem.php?id=3529

 

有一张n*m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。

20000 组询问  n<=1e5

 

f(k)表示 k 的 约数和

g(k)表示 技术分享图片

f(k)的求法:

http://www.cnblogs.com/TheRoadToTheGold/p/8228969.html

g(k)的求法:

http://www.cnblogs.com/TheRoadToTheGold/p/6609495.html

 

假设没有a的限制

不妨令n<=m

技术分享图片

技术分享图片

 令i*d=t,把后面两个下取整提到前面

技术分享图片

技术分享图片

技术分享图片

预处理出F(t),除法分块便可以在O(sqrt(n))求解

但是现在有f(i)<=a 的限制

离线处理,读入所有的询问

所以把f(i)按f(i)的值从小到大排序

询问按a的值从小到大排序

用树状数组维护当前F(t)的值

在处理这个询问之前

找出所有<=本次询问a的f(i)

在树状数组中i及i的倍数位置加上f(i)

 

取模不用管,自然溢出即可 

 

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001
#define M 20001

typedef long long LL;

int T;

int miu[N];

int p[N];
bool vis[N];

struct nodef
{
    int d,val;
}f[N];
int c[N];

bool cmpf(nodef A,nodef B)
{
    if(A.val!=B.val) return A.val<B.val;
    return A.d<B.d;
}

struct Query
{
    int id;
    int n,m,a;
}Q[M];

bool cmpQ(Query A,Query B)
{
    return A.a<B.a;
}

int ans[M];

struct BIT
{
    int s[N];
    
    #define lowbit(x) x&-x
    
    void add(int x,int val)
    {
        while(x<N-1)
        {
            s[x]=s[x]+val;
            x+=lowbit(x);
        }
    }
    
    int query(int x)
    {
        int sum=0;
        while(x)
        {
            sum=sum+s[x];
            x-=lowbit(x);
        }
        return sum;
    }
    
}Bit;

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c==-) f=-1; c=getchar(); }
    while(isdigit(c))  { x=x*10+c-0; c=getchar(); }
    x*=f;
}

void pref()
{
    int cnt=0;
    miu[1]=1;
    f[1].d=1;
    f[1].val=1;
    for(int i=2;i<N;++i)
    {
        f[i].d=i;
        if(!vis[i])
        {
            p[++cnt]=i;
            miu[i]=-1;
            f[i].val=i+1;
            c[i]=1;
        }
        for(int j=1;j<=cnt;++j)
        {
            if(i*p[j]>=N) break;
            vis[i*p[j]]=true;
            if(i%p[j]==0)
            {
                f[i*p[j]].val=f[i].val*p[j]+c[i];
                c[i*p[j]]=c[i];
                break;
            }
            miu[i*p[j]]=-miu[i];
            f[i*p[j]].val=f[i].val*(p[j]+1);
            c[i*p[j]]=f[i].val;
        }
    }
    sort(f+1,f+N,cmpf);
}

void init()
{
    read(T);
    for(int i=1;i<=T;++i)
    {
        read(Q[i].n);
        read(Q[i].m);
        read(Q[i].a);
        Q[i].id=i;
    }
    sort(Q+1,Q+T+1,cmpQ);
}

void solve()
{
    int nowQ=1;
    while(Q[nowQ].a<=0) nowQ++;
    int nowd=1;
    int j,res;
    int tot,lastsum,nowsum;
    for(;nowQ<=T;++nowQ)
    {
        while(nowd<N && f[nowd].val<=Q[nowQ].a)
        {
            for(int i=f[nowd].d;i<N;i+=f[nowd].d)
                Bit.add(i,f[nowd].val*miu[i/f[nowd].d]);
            nowd++;
        }
        if(Q[nowQ].n>Q[nowQ].m) swap(Q[nowQ].n,Q[nowQ].m);
        tot=lastsum=0;
        for(int i=1;i<=Q[nowQ].n;i=j+1)
        {
            j=min(Q[nowQ].n/(Q[nowQ].n/i),Q[nowQ].m/(Q[nowQ].m/i));
            nowsum=Bit.query(j);
            res=nowsum-lastsum;
            res=res*(Q[nowQ].n/i)*(Q[nowQ].m/i);
            tot+=res;
            lastsum=nowsum;
        }
        tot+= tot<0 ? 1LL<<31 : 0;
        ans[Q[nowQ].id]=tot;
    }
    for(int i=1;i<=T;++i) cout<<ans[i]<<\n;
}

int main()
{
    pref();
    init();
    solve();
}

 

bzoj千题计划205:bzoj3529: [Sdoi2014]数表

标签:namespace   约数   分享图片   last   bubuko   bool   不用   geo   log   

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8241930.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!