您的位置:首页 > 其它

【51nod】【算法马拉松14】1586 约数和

2016-06-18 00:13 218 查看
传送门:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1586

题面:

有三个下标从1 到n 的数组a、b、c 。a 数组初始全为0。

b[i]=∑ j|i a[j]

c[i]=∑ j|i b[j]

需要进行下列操作:

1 x y :将a[x] 加上y

2 x :询问当前c[x] 的值

Input

第一行两个整数,n 和q ,分别表示数组下标范围和操作次数。(1<=n,q<=1,000,000 )

接下来q 行,描述一个操作。(x 随机,1<=x<=n ,1<=y<=10 6 )

Output

对于每一个第二种操作输出一个答案。

对于每个a 数组元素,对它的下标整数倍b数组元素产生贡献,然后再对其下标整数倍的c 数组元素产生影响。

那么对于a[x] 和c[y] ,通过简单的推算就可以知道a[x] 对c[y] 的贡献倍数为yx 的约数个数倍

(可以理解为从x 到y 有多少种变换方法)

然后就可以使用正常的方法去维护了(本题单点查改,不需要数据结构维护)

于是预处理1000000 以内每个数的约数个数。

维护的方法有两种

第一种:每修改一个a ,就修改其所有相关的c

第二种:每查询一个c ,就查询其所有相关的a

因为n的约数个数是n √ 级别的,所以说,然而一个数的倍数可能是n 级别的

于是乎,一般情况下都会选择第二种维护方式(每次查询n √ ),这么想的同学应该在51nod 上从第13 个点开始挂……(2500ms 左右跑过时间最长点)

这一道题中有个重要条件:x 随机

也就是说,x 的期望大小为500000 。这也就意味着,对于第二种维护方式,还是每次查询n √ 的期望查询次数。但是对于第一种维护方式,每次修改的期望修改次数只有2 。

于是这题选择第一种维护方式更优(快了不是一点),有人说这题读入输出优化一个不能少,少一个就T。然后……我就华丽丽地一个都没加……硬是过了这题……(1300ms )

#include<stdio.h>
#define N 1000050
#define LL long long

LL ans,a
;
int f
,n,q,c,tot,U;

int main()
{
scanf("%d%d",&n,&q);
for (int i=1;i<=n;i++) for (int j=i;j<=n;j+=i) f[j]++;
for (int c;q;q--)
{
scanf("%d",&c);
if (c==1)
{
scanf("%d%d",&U,&c);
for (int i=U,j=1;i<=n;i+=U,j++) a[i]+=c*f[j];
}
else
{
scanf("%d",&c);
printf("%I64d\n",a[c]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: