51nod1586 约数和

15 篇文章 0 订阅
2 篇文章 0 订阅
基准时间限制:2 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

有三个下标从1到n的数组a、b、c。

a数组初始全为0。

 b[i]=j|ia[j] 

 c[i]=j|ib[j] 

需要进行下列操作:

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

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


j | i 表示j是i的约数。
由于数据比较多,请用输入挂。
以下供参考。
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const  int  BufferSize = 1 << 16 ;
char  buffer [ BufferSize ] , * head , * tail ;
inline  char  Getchar ( )  {
     if ( head == tail )  {
         int  l = fread ( buffer , 1 , BufferSize , stdin ) ;
         tail = ( head = buffer ) + l ;
     }
     return  * head ++ ;
}
inline  int  read ( )  {
     int  x = 0 , f = 1 ; char  c = Getchar ( ) ;
     for ( ; ! isdigit ( c ) ; c = Getchar ( ))  if ( c == '-' )  f = -1 ;
     for ( ; isdigit ( c ) ; c = Getchar ( ))  x = x * 10 + c - '0' ;
     return  x * f ;
}
 
Input
第一行两个整数,n和q,分别表示数组下标范围和操作次数。(1<=n,q<=1,000,000)
接下来q行,描述一个操作。(x随机,1<=x<=n,1<=y<=10^6)
Output
对于每一个第二种操作输出一个答案。
Input示例
5 5
1 2 4
2 2
2 4
1 1 3
2 5
Output示例
4
8
6

题解:这题也是醉了。用暴力就行。

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

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

 PS:只有当y为x倍数的时候才可能有贡献,不妨设y为x的z倍,那么a-b-c要有贡献的话b是a的x1倍,c是b的y1倍,c是a的x1*y1倍,那么只有x1*y1=z时,才有贡献,也就是x1为z的约数是才有贡献。所以每对x,y的贡献为y*(z的约数的个数)

(可以理解为从x 到y 有多少种变换方法) 
然后就可以使用正常的方法去维护了(本题单点查改,不需要数据结构维护)

于是预处理1000000 以内每个数的约数个数。 
维护的方法有两种 
第一种:每修改一个a ,就修改其所有相关的c 
第二种:每查询一个c ,就查询其所有相关的a 
因为n的约数个数是n √ 级别的,所以说,然而一个数的倍数可能是n 级别的 
于是乎,一般情况下都会选择第二种维护方式(每次查询n √ ),这么想的同学应该在51nod 上从第13 个点开始挂……(2500ms 左右跑过时间最长点)

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

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

于是这题选择第一种维护方式更优(快了不是一点)。 

题解转自:点击打开链接




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值