51Nod 1586 约数和
来源:互联网 发布:信息软件 编辑:程序博客网 时间:2024/06/08 14:43
题面:
有三个下标从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 。
于是这题选择第一种维护方式更优(快了不是一点)。
题解转自:http://blog.csdn.net/pure_w/article/details/51703311
//我的代码输入输出都要用挂优化,不然会t = =!#include<bits/stdc++.h>const int INF = 0x3f3f3f3f;const int Maxn = 1000005;#define ll long long#define mem(x,y) memset(x,y,sizeof(x))using namespace std;// 输入输出外挂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;}void Out(ll a) { if (a < 0) { putchar('-'); a = -a; } if (a >= 10) Out(a / 10); putchar(a % 10 + '0');}int f[Maxn];ll c[Maxn];int main() { int n, q, A, B, C; n = read(); q = read(); for (int i = 1; i <= n ; i++) for (int j = i ; j <= n; j += i) f[j]++; for (int k = 1; k <= q; k++) { A = read(); if (A == 2) { B = read(); Out(c[B]); putchar('\n'); } else { B = read(); C = read(); for (int i = B, j = 1; i <= n; i += B, j++) c[i] += C * f[j]; } }}
// 大佬的代码,为啥不T?#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]); } }}
- 51nod 1586 约数和
- 51nod 1586 约数和
- 51Nod 1586 约数和
- 51Nod-1586-约数和
- 51nod 1586 约数和
- [杜教筛 约数和前缀和] 51Nod 1220 约数之和
- 【51nod】【算法马拉松14】1586 约数和
- 51nod 1584 加权约数和
- 51nod 1584 加权约数和
- 51Nod-1220-约数之和
- 51nod 1220 约数之和
- 51nod 1220 约数之和
- [莫比乌斯反演] 51Nod 1584 加权约数和
- 51nod1584 加权约数和
- 约数个数及约数和
- PE 439 Sum of sum of divisors | 51nod 1220 约数之和
- 51nod oj 1116 【进制问题】 1179【约数打表】
- 51nod 1165 整边直角三角形的数量 【数学:公式--求约数】
- ImageLoader_缓存 写入读取sd卡
- 《TCP/IP详解 卷1:协议》 读书笔记 第十章 动态选路协议
- Leetcode 409(Java)
- 永恒之蓝源码进一步剖析
- Netty protobuf使用,自定义Encoder 和DeCoder
- 51Nod 1586 约数和
- linux下配置tomcat的虚拟路径
- 内部类
- android 耳机插拔流程
- 快速安装scrapy
- MSP430FR5969内存分配的问题
- shell正则表达式使用规则整理
- openssl命令 来自: http://man.linuxde.net/openssl
- 离散题目6