zoukankan      html  css  js  c++  java
  • 【洛谷P3312】数表

    题目

    题目链接:https://www.luogu.com.cn/problem/P3312
    有一张 \(n\times m\) 的数表,其第 \(i\) 行第 \(j\) 列(\(1\le i\le n\)\(1\le j\le m\))的数值为能同时整除 \(i\)\(j\) 的所有自然数之和。给定 \(a\),计算数表中不大于 \(a\) 的数之和。

    思路

    先不考虑 \(a\) 的限制,那么 \((i,j)\) 的数值即为 \(\gcd(i,j)\) 的因子之和(设为 \(g(i)\))。\(g(i)\) 可以 \(O(n\log n)\) 预处理出。

    \[ans=\sum^{n}_{i=1}g(i)\times \sum^{\min(n,m)}_{d|i}\mu(\frac{i}{d})\lfloor{\frac{n}{i}}\rfloor\lfloor{\frac{m}{i}}\rfloor \]

    \[=\sum^{n}_{i=1}\lfloor{\frac{n}{i}}\rfloor\lfloor{\frac{m}{i}}\rfloor\sum^{\min(n,m)}_{i|d}g(d)\mu(\frac{i}{d}) \]

    当有 \(a\) 的限制时,只有 \(g(x)\leq a\)\(g(x)\) 才可以产生贡献。所以我们将询问按 \(a\) 排序,数字 \(x\)\(g(x)\) 排序,对于一个询问 \(a\)\(g(x)\leq a\) 的所有 \(g(x)\)\(x\) 倍数的贡献加上,然后再询问一段区间的和。
    用树状数组处理即可。然后就是整除分块乱搞了。
    时间复杂度 \(O(Q\sqrt{n}+Q\log^2 n)\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned int uint;
    
    const int N=100010;
    int Q,tot,prm[N],mu[N],g[N];
    uint ans[N];
    bool v[N];
    
    struct Query
    {
    	int n,m,a,id;
    }ask[N];
    
    struct node
    {
    	int g,id;
    }a[N];
    
    bool cmp1(Query x,Query y)
    {
    	return x.a<y.a;
    }
    
    bool cmp2(node x,node y)
    {
    	return x.g<y.g;
    }
    
    void findprm(int n)
    {
    	mu[1]=1;
    	for (int i=2;i<=n;i++)
    	{
    		if (!v[i])
    			prm[++tot]=i,mu[i]=-1;
    		for (int j=1;j<=tot;j++)
    		{
    			if (i>n/prm[j]) break;
    			v[prm[j]*i]=1; mu[prm[j]*i]=-mu[i];
    			if (!(i%prm[j]))
    			{
    				mu[i*prm[j]]=0;
    				break;
    			}
    		}
    	}
    }
    
    struct BIT
    {
    	uint c[N];
    	
    	void add(int x,uint v)
    	{
    		for (int i=x;i<N;i+=i&-i)
    			c[i]+=v;
    	}
    	
    	uint query(int x)
    	{
    		uint ans=0;
    		for (int i=x;i;i-=i&-i)
    			ans+=c[i];
    		return ans;
    	}
    }bit;
    
    int main()
    {
    	findprm(N-10);
    	for (int i=1;i<=N-10;i++)
    		for (int j=i;j<=N-10;j+=i)
    			g[j]+=i;
    	for (int i=1;i<=N-10;i++)
    		a[i]=(node){g[i],i};
    	sort(a+1,a+1+N-10,cmp2);
    	scanf("%d",&Q);
    	for (int i=1;i<=Q;i++)
    	{
    		scanf("%d%d%d",&ask[i].n,&ask[i].m,&ask[i].a);
    		ask[i].id=i;
    	}
    	sort(ask+1,ask+1+Q,cmp1);
    	for (int i=1,j=1;i<=Q;i++)
    	{
    		for (;j<=N-10 && a[j].g<=ask[i].a;j++)
    			for (int k=a[j].id;k<=N-10;k+=a[j].id)
    				bit.add(k,1U*mu[k/a[j].id]*a[j].g);
    		int n=ask[i].n,m=ask[i].m;
    		for (int l=1,r;l<=min(n,m);l=r+1)
    		{
    			r=min(n/(n/l),m/(m/l));
    			ans[ask[i].id]+=1U*(n/l)*(m/l)*(bit.query(r)-bit.query(l-1));
    		}
    	}
    	for (int i=1;i<=Q;i++)
    		printf("%d\n",(int)(2147483647U&ans[i]));
    	return 0;
    }
    
  • 相关阅读:
    【新特性速递】卡片式表格,Yeah~~~
    6个最佳DevOps播客
    在裸金属服务器Bare Metal上Kubernetes
    保护Java应用程序不被窃取数据和源代码2
    家政服务行业动态
    15个免费数据集数据科学项目
    性能测试工具
    利用Apache Pulsar的实时边缘计算
    软件开发的八个误解
    如何防止范围蔓延
  • 原文地址:https://www.cnblogs.com/stoorz/p/13736808.html
Copyright © 2011-2022 走看看