51nod 1586 约数和

来源:互联网 发布:浙大网新恒天软件福利 编辑:程序博客网 时间:2024/06/08 02:40

可以通过b数组来找到a数组和c数组的关系。假设现在更新a[x],求c[y],只要找到一个a[x]对c[y]贡献了多少次即可。b对c产生直接的贡献。则c[y]来自b的贡献就是y的因子的个数,在y的这些因子中,如果他是x的倍数,则有一次a[x]的贡献,则y的因子中有多少因子是x的倍数,a[x]就对c[y]贡献了多少次,y的因子中有y/x个数是x的倍数,所以a[x]对c[y]贡献了y/x次。约数的个数是sqrt(n)级别的,就暴力枚举就好了。
参考:http://blog.csdn.net/pure_w/article/details/51703311

#include <bits/stdc++.h>using namespace std;const int MAXN = 1e6+10;int f[MAXN];int n,q;long long c[MAXN];template <class T>inline bool scan_d(T &ret){    char c;    int sgn;    if(c=getchar(),c==EOF) return 0; //EOF    while(c!='-'&&(c<'0'||c>'9')) c=getchar();    sgn=(c=='-')?-1:1;    ret=(c=='-')?0:(c-'0');    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');    ret*=sgn;    return 1;}inline void out(long long x){    if(x>9) out(x/10);    putchar(x%10+'0');}void init(){    for(int i = 1; i <= n; ++i)        for(int j = i; j <= n; j += i)            f[j]++;}int main(){    scan_d(n);    scan_d(q);    init();    int op,x,y;    while(q--)    {        scan_d(op);        if(op == 1)        {            scan_d(x);            scan_d(y);            for(int i = x, j = 1; i <= n; i += x,++j)                c[i] += y*f[j];        }        else        {            scan_d(x);            out(c[x]);            puts("");        }    }    return 0;}