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

来源:互联网 发布:苹果手机网络时间校准 编辑:程序博客网 时间:2024/06/04 22:22

传送门:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1586

题面:

有三个下标从1 n 的数组abc 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 longLL ans,a[N];int f[N],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]);        }    }}
0 0
原创粉丝点击