题目:
洛谷P3396
大意:一个序列,两种操作,单点修改和查询sum(a[xk+y]),给出x和y,k为任意一个满足xk+y<=n的数。
分析:很显然的想法是暴力,O(1)修改,O(n/k)查询,显然会TLE,但又不是不可取,因为当k>sqrt(n)时,一次查询就是O(sqrt(n))的,这又不会TLE。问题变为求sqrt(n)>k的贡献了,我们可以搞出一个数组f[x][y]表示询问为x,y的答案,有
f[j,i%j]+=a[i] (1<=i<=n;j<=sqrt(n)),每次修改把f[j,x%j]改掉即可,预处理O(n^1.5),修改O(n^0.5)。就可以过了。
(和分块有个鬼关系)
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=150005;
using namespace std;
int i,j,block,n,m;
int a[maxn],f[1001][1001];
char op[1];
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
block=trunc(sqrt(n));
for (i=1;i<=n;i++)
{
for (j=1;j<=block;j++)
{
f[j][i%j]+=a[i];
}
}
for (i=1;i<=m;i++)
{
scanf("%s",&op);
int x,y;
scanf("%d%d",&x,&y);
if (op[0]=='C')
{
int delta=y-a[x];
a[x]=y;
for (j=1;j<=block;j++)
{
f[j][x%j]+=delta;
}
}
else
{
int ans=0;
if (x>block)
{
j=y;
while (j<=n)
{
ans+=a[j];
j=j+x;
}
}
else
{
ans=f[x][y];
}
printf("%d\n",ans);
}
}
}