zoukankan      html  css  js  c++  java
  • [SDOI2014]数表

    [SDOI2014]数表

    一.题意简述

    ​ 题目要求的是

    [sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}sigma(gcd(i,j))<a\ ]

    那个是除数函数啦。(不知道的自己百度)

    二.解题思路

    ​ 有什么思路,干就完了,奥利给!!这个(<a)很碍眼,反手扔了不虚他。于是要求解

    [sumlimits_{d=1}^{n}sumlimits_{i=1}^{lfloorfrac{n}{d} floor} sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sigma(d)[gcd(i,j)=1]\ ]

    虽说这一步跨度有点大,但是是可以理解的,对于大多数gcd都会选择起手枚举gcd的值,而这里的(i,j)相当于是系数一样的东西叭。由于是枚举的最大公约数,所以(i,j)要互质才好,这是常规操作。

    现在发现了一只野生的(epsilon),(如果读不懂这句话请先看这篇文章),那么就把他换成(mu).(基操)

    [sumlimits_{d=1}^{n}sumlimits_{i=1}^{lfloorfrac{n}{d} floor} sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sigma(d)sumlimits_{k|gcd(i,j)}^{}mu(k)\ ]

    然后走一波换位+基操

    [sumlimits_{d=1}^{n}sigma(d)sumlimits_{k=1}^{lfloorfrac{n}{d} floor}mu(k) lfloorfrac{n}{dk} floorlfloorfrac{m}{dk} floor\ ]

    其实这里也是在枚举gcd,跟上面思路差不多,再不想让d干扰,换了个位置。

    [(p=dk)sumlimits_{p=1}^{n}lfloorfrac{n}{p} floorlfloorfrac{m}{p} floorsumlimits_{d|p}^{}mu(d)sigma(frac{p}{d}) ]

    乘积形式的分母不好看,换一手元,交换位置。

    本来这样就好了,但是题目有个a。于是想着怎么把他找回来,加进去吧

    [(p=dk)sumlimits_{p=1}^{n}lfloorfrac{n}{p} floorlfloorfrac{m}{p} floorsumlimits_{d|p}^{}mu(d)sigma(frac{p}{d})\ sumlimits_{d|p}^{}mu(d)sigma(frac{p}{d})<a ]

    这个应该能看懂,首先以求和符号作为分界记后面的那一堆为(g(p))好了,然后考虑一下(mu)函数的性质,了解到(sigma(frac{p}{d})<=a)才对答案有贡献,然而又有多组数据,并且除数函数值的大小跟参数大小没有什么关系,是乱的。(开始暴躁)

    不过不慌,我们把(sigma)和a都拉来排个序,新的a出现时便用符合条件的(sigma)去更新(g),再用数论分块算一算。(还是看代码吧)

    三.CODE

    #define ll long long
    #define m_for(i,a,b) for(int i=a;i<=b;++i)
    #define lowbit(x) x&(-x)
    inline int read() {
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9') {
    		if(ch=='-')w=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    	return s*w;
    }
    const int MAXN=1e5+1,MAXQ=2*1e4+1;
    ll mod=1LL<<31;
    int prime[MAXN],tot,mu[MAXN];
    ll g[MAXN];
    pair<int,int> sigma[MAXN];
    bool vis[MAXN];
    void m_p(int x){
    	sigma[1].first=sigma[1].second=1;
    	mu[1]=1;
    	m_for(i,2,x){
    		sigma[i].first++;
    		if(!vis[i])prime[++tot]=i,mu[i]=-1;
    		for(int j=1;j<=tot&&i*prime[j]<=x;++j){
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    			mu[i*prime[j]]=-mu[i];
    		}
    		for(int j=i;j<=x;j+=i)sigma[j].first=(sigma[j].first+i)%mod;
    		sigma[i].second=i;
    	}
    	sort(sigma+1,sigma+x+1);
    }
    struct alf{
    	int n,m,a,id;
    }que[MAXQ];
    bool cmp(alf c,alf b){
    	return c.a<b.a;
    }
    int tree_g[MAXN];
    void change(int x,int y){
    	for(;x<MAXN;x+=lowbit(x))tree_g[x]+=y;
    }
    ll sum(int x){
    	ll res=0;
    	for(;x>0;x-=lowbit(x))res+=tree_g[x];
    	return res;
    }
    ll solve(int n,int m){
    	if(n>m)swap(n,m);
    	ll res=0;
    	for(int l=1,r;l<=n;l=r+1){
    		r=min(n/(n/l),m/(m/l));
    		res+=1LL*(n/l)*(m/l)*(sum(r)-sum(l-1));
    		res%=mod;
    	}
    	return (res%mod+mod)%mod;
    }
    int q,res=1;
    int ans[MAXQ];
    int main(){
    m_p(MAXN);
    q=read();
    m_for(i,1,q)que[i].id=i,que[i].n=read(),que[i].m=read(),que[i].a=read();
    sort(que+1,que+q+1,cmp);
    m_for(i,1,q){
    	while(sigma[res].first<=que[i].a&&res<=MAXN){
    		for(int j=1;j*sigma[res].second<=MAXN;++j)
    			change(j*sigma[res].second,mu[j]*sigma[res].first);
    		res++;
    	}
    	ans[que[i].id]=solve(que[i].n,que[i].m)%mod;
    }
    m_for(i,1,q)cout<<ans[i]<<endl;
    return 0;
    }
    
  • 相关阅读:
    poj 3278 catch that cow
    POJ 1028 Web Navigation
    poj 2643 election
    hdu 1908 double queues
    hdu_2669 Romantic(扩展欧几里得)
    0/1背包 dp学习~6
    校验码
    最长上升子序列(LIS经典变型) dp学习~5
    LCS最长公共子序列~dp学习~4
    最长上升子序列(LIS) dp学习~3
  • 原文地址:https://www.cnblogs.com/clockwhite/p/12256469.html
Copyright © 2011-2022 走看看