bzoj 3529
非常好的一道莫比乌斯反演题,对提升自己的能力有很大帮助。
首先我们分析一下题意:题意让我们求,其中
那么我们首先对后面的式子进行一下变形,变形过程详见https://blog.csdn.net/lleozhang/article/details/89093689
于是最后变成了这个样子:
但是这个式子还是不好,所以我们改变一下枚举顺序,先枚举d
于是上式改为:
可以发现右侧的式子是一个反演的形式,于是记
于是原式=
先预处理出每个数的约数和(线性筛),然后利用数论分块+前缀和计算即可
等等,难道就这么简单?
当然不会了!!!
再仔细想想,我们上面的过程根本没有管a啊!
由于对k是有要求的,所以我们在预处理的时候如果不知道询问中的a,就没有办法确认对于每个d,哪个k是可用的!
那怎么办?
离线!
我们先将所有询问按照a从小到大排序,这样前面的询问所能用到的k后面的询问一定也可以用,这样我只需要每次将因为a变大而变得可用的k加入即可!
可是我们的要求是,所以仅仅对a排序是不够的,由于约数和并不具有单调性,所以我们还要对约数和排序,然后对于每个询问,将新变得合法的k对应地累计进f(d)就可以了
由于这是一个动态的过程,使用树状数组维护f的前缀和,这样就既支持修改,又支持求前缀和了。
贴代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define mode (1ll<<31)
using namespace std;
struct Ques
{
int n,m,a,num;
}q[100005];
int pri[100005];
bool used[100005];
int mu[100005];
struct SIG
{
ll si;
int num;
}sig[100005];
int mi[100005];
ll v[100005];
ll ret[100005];
int s[100005];
int cnt=0;
int lowbit(int x)
{
return x&(-x);
}
void ins(int x,ll y)
{
while(x<=100000)
{
s[x]+=y;
x+=lowbit(x);
}
}
int get_sum(int x)
{
int ans=0;
while(x)
{
ans+=s[x];
x-=lowbit(x);
}
return ans;
}
ll pow_mul(ll x,int y)
{
ll ans=1;
while(y)
{
if(y&1)
{
ans*=(ll)x;
}
x*=x;
y/=2;
}
return ans;
}
void init()
{
mu[1]=1;
sig[1].si=1;
sig[1].num=1;
for(int i=2;i<=100000;i++)
{
if(!used[i])
{
pri[++cnt]=i;
mu[i]=-1;
sig[i].si=i+1;
sig[i].num=i;
v[i]=i+1;
mi[i]=1;
}
for(int j=1;j<=cnt&&i*pri[j]<=100000;j++)
{
used[i*pri[j]]=1;
if(i%pri[j]==0)
{
mu[i*pri[j]]=0;
ll temp=v[i]+pow_mul(pri[j],mi[i]+1);
sig[i*pri[j]].si=sig[i].si/v[i]*temp;
sig[i*pri[j]].num=i*pri[j];
mi[i*pri[j]]=mi[i]+1;
v[i*pri[j]]=temp;
break;
}
mu[i*pri[j]]=-mu[i];
sig[i*pri[j]].si=sig[i].si*(pri[j]+1);
sig[i*pri[j]].num=i*pri[j];
v[i*pri[j]]=pri[j]+1;
mi[i*pri[j]]=1;
}
}
}
bool cmp(Ques x,Ques y)
{
return x.a<y.a;
}
bool cmp1(SIG x,SIG y)
{
return x.si<y.si;
}
int solve(int x,int y)
{
if(x>y)
{
swap(x,y);
}
int ans=0;
int last=0;
for(int i=1;i<=x;i=last+1)
{
last=min(x/(x/i),y/(y/i));
ans+=(get_sum(last)-get_sum(i-1))*(x/i)*(y/i);
}
return ans;
}
int T;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
T=read();
init();
int maxn=0;
for(int i=1;i<=T;i++)
{
q[i].n=read(),q[i].m=read(),q[i].a=read();
q[i].num=i;
maxn=max(maxn,max(q[i].n,q[i].m));
}
sort(q+1,q+T+1,cmp);
sort(sig+1,sig+100001,cmp1);
int las=1;
for(int i=1;i<=T;i++)
{
while(sig[las].si<=q[i].a&&las<=100000)//枚举k
{
for(int j=1;j*sig[las].num<=maxn;j++)//枚举倍数
{
ins(j*sig[las].num,sig[las].si*mu[j]);
}
las++;
}
ret[q[i].num]=solve(q[i].n,q[i].m)&2147483647;
}
for(int i=1;i<=T;i++)
{
printf("%d\n",ret[i]);
}
return 0;
}
bzoj 3529的更多相关文章
- 【莫比乌斯反演】关于Mobius反演与gcd的一些关系与问题简化(bzoj 2301 Problem b&&bzoj 2820 YY的GCD&&BZOJ 3529 数表)
首先我们来看一道题 BZOJ 2301 Problem b Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd( ...
- 【BZOJ 3529】 [Sdoi2014]数表 (莫比乌斯+分块+离线+树状数组)
3529: [Sdoi2014]数表 Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有 ...
- BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]
3529: [Sdoi2014]数表 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1399 Solved: 694[Submit][Status] ...
- BZOJ 3529 数表(莫比乌斯反演)
http://www.lydsy.com/JudgeOnline/problem.php?id=3529 思路:令F(i)为i的约数和, 1<=x<=n,1<=y<=m G(i ...
- bzoj 3529 数表
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3529 题目大意:令F(i)为i的约数和,多次询问对于1<=x<=n,1< ...
- ●BZOJ 3529 [Sdoi2014]数表
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3529 题解: 莫比乌斯反演. 按题目的意思,令$f(i)$表示i的所有约数的和,就是要求: ...
- BZOJ 3529 数表(莫比乌斯+树状数组)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3529 题意:有一张n×m的数表,其第i行第j列的数值为能同时整除i和j的所有自然数 ...
- bzoj 3529: [Sdoi2014]数表
#include<cstdio> #include<iostream> #include<algorithm> #define M 200009 //#define ...
- 【BZOJ 3529】【SDOI 2014】数表
看Yveh的题解,这道题卡了好长时间,一直不明白为什么要······算了当时太naive我现在都不好意思说了 #include<cstdio> #include<cstring> ...
- bzoj 3529 数表 莫比乌斯反演+树状数组
题目大意: 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. ...
随机推荐
- ReentrantLock(重入锁)的使用
//效果和synchronized一样,都可以同步执行,lock方法获得锁,unlock方法释放锁public class MyService { private Lock lock = new Re ...
- Deep Learning Tutorial - Multilayer perceptron
Multilayer perceptron:多层感知器 本节实现两层网络(一个隐层)作为分类器实现手写数字分类.引入的内容:激活函数(双曲正切.L1和L2正则化).Theano的共享变量.grad.f ...
- openGL之坐标变换
- struts2框架学习之第三天
day03 上传下载 1 上传下载组件介绍 l jspSmartUpload(model1的年代): l apache-commons-fileupload,Struts2默认上传组 ...
- 在Centos7 上安装SVN
https://blog.csdn.net/crossangles_2017/article/details/78553266 1.安装 使用yum安装非常简单: yum install subver ...
- Select2日常操作集合
1.获得多选值 var arraySelected = $('#carTypes').select2("data"); var carTypesDesc = ''; for (va ...
- SQL Server循环
1.普通循环 DECLARE @i int BEGIN WHERE Uid=@i --PRINT @i END 2.游标循环(没有事务) ---游标循环(没有事务) BEGIN DECLARE @a ...
- 发布python模块
首先要写好模块和setup.py,把他们放在同一个文件夹下,图例是放在了stuManage文件夹下,setup.py具体内容如下: 然后打开终端,切到stuManage文件夹下开始发布 现在就可以跟p ...
- Visual Studio Code使用指南
简介 Visual Studio Code是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮.智能代码补全.自定义热键.括号匹配.代码片段.代码对比 Diff.GIT 等特性 ...
- python-模块入门二(模块循环导入,区分python文件的两种用途,模块搜索路径,软件开发的目录规范)
一.模块的循环导入问题 run.py # import m1 # 第一次导入 m1.py # 错误示范 ''' print('正在导入m1') from m2 import y #第一次导入m2 x= ...