传送门:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1586
题面:
有三个下标从 1 1 1到 n n n的数组 a 、 b 、 c a、b、c a、b、c。 a a a数组初始全为0。
b
[
i
]
=
∑
j
∣
i
a
[
j
]
b[i]=\sum\limits_{j|i}a[j]
b[i]=j∣i∑a[j]
c
[
i
]
=
∑
j
∣
i
b
[
j
]
c[i]=\sum\limits_{j|i}b[j]
c[i]=j∣i∑b[j]
需要进行下列操作:
1
x
x
x
y
y
y :将
a
[
x
]
a[x]
a[x]加上
y
y
y
2
x
x
x :询问当前
c
[
x
]
c[x]
c[x]的值
Input
第一行两个整数,
n
n
n和
q
q
q,分别表示数组下标范围和操作次数。(
1
<
=
n
,
q
<
=
1
,
000
,
000
1<=n,q<=1,000,000
1<=n,q<=1,000,000)
接下来
q
q
q行,描述一个操作。(
x
x
x随机,
1
<
=
x
<
=
n
1<=x<=n
1<=x<=n,
1
<
=
y
<
=
1
0
6
1<=y<=10^6
1<=y<=106)
Output
对于每一个第二种操作输出一个答案。
对于每个
a
a
a数组元素,对它的下标整数倍b数组元素产生贡献,然后再对其下标整数倍的
c
c
c数组元素产生影响。
那么对于
a
[
x
]
a[x]
a[x]和
c
[
y
]
c[y]
c[y],通过简单的推算就可以知道
a
[
x
]
a[x]
a[x]对
c
[
y
]
c[y]
c[y]的贡献倍数为
y
x
\frac{y}{x}
xy的约数个数倍
(可以理解为从
x
x
x到
y
y
y有多少种变换方法)
然后就可以使用正常的方法去维护了(本题单点查改,不需要数据结构维护)
于是预处理
1000000
1000000
1000000以内每个数的约数个数。
维护的方法有两种
第一种:每修改一个
a
a
a,就修改其所有相关的
c
c
c
第二种:每查询一个
c
c
c,就查询其所有相关的
a
a
a
因为n的约数个数是
n
\sqrt{n}
n级别的,所以说,然而一个数的倍数可能是
n
n
n级别的
于是乎,一般情况下都会选择第二种维护方式(每次查询
n
\sqrt{n}
n),这么想的同学应该在
51
n
o
d
51nod
51nod上从第
13
13
13个点开始挂……(
2500
m
s
2500ms
2500ms左右跑过时间最长点)
这一道题中有个重要条件: x x x随机
这也就意味着,对于第二种维护方式,还是每次查询 n \sqrt{n} n的期望查询次数。但是对于第一种维护方式,每次修改的期望修改次数只有 log n \log n logn。
于是这题选择第一种维护方式更优(快了不是一点),有人说这题读入输出优化一个不能少,少一个就T。然后……我就华丽丽地一个都没加……硬是过了这题……( 1300 m s 1300ms 1300ms)
#include<stdio.h>
#define N 1000050
#define LL long long
LL 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]);
}
}
}