题目:
题解:
一道很奇怪的题目,我直接复制题解了。
首先,题目要我们求的东西,就是下面的代码:
for(i=k;i<=n;i+=p) ans+=value[i];
即:从 k开始,每隔p个数取一个数,求它们的和。这个算法的复杂度是O(n^2) 的。
令答案为ans[p][k],表示模数是p,余数是k。
那么,对于第i个数,如何处理它对ans的贡献呢?
for(p=1;p<=n;p++) //枚举模数
ans[p][i%p]+=value[i]; //处理对应的贡献
看起来不错,但还是n^2啊
所以我们只处理
[1,n−−√]
[
1
,
n
]
以内的p
于是预处理的复杂度降到了
O(nn−−√)
O
(
n
n
)
接着考虑询问。如果询问的p < size ,那显然可以O(1)给出回答。
如果p超过size,我们就暴力统计并回答。因为
p>n−−√
p
>
n
,所以少于
n−−√
n
个数对答案有贡献。
接着考虑修改。显然我们把p
代码:
#include <cstdio>
#include <cmath>
using namespace std;
int a[150005],ans[390][150005];
//ans[i][j]模数为i时余数为j的贡献
int main()
{
int n,m,x,y,i,j;
scanf("%d%d",&n,&m);int si=sqrt(n);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
for (i=1;i<=n;i++)
for (j=1;j<=si;j++) ans[j][i%j]+=a[i];
for (i=1;i<=m;i++)
{
char st=getchar();while (st!='A' && st!='C') st=getchar();
scanf("%d%d",&x,&y);
if (st=='A')
{
if (x<=si) printf("%d\n",ans[x][y]);
else
{
int ans=0;
for (j=y;j<=n;j+=x) ans+=a[j];
printf("%d\n",ans);
}
}else
{
for (j=1;j<=si;j++) ans[j][x%j]=ans[j][x%j]-a[x]+y;
a[x]=y;
}
}
}