51nod 1586 约数和

题目描述

有三个下标从1到n的数组a、b、c。
a数组初始全为0。
b[i]=j|ia[j],c[i]=j|ib[j]
需要进行下列操作:
1 x y :将a[x]加上y
2 x :询问当前c[x]的值

数据范围(1<=n,q<=1,000,000,x随机,1<=x<=n,1<=y<=10^6)

考虑用a表示c

c[i]=j|ib[j]=j|ij|ja[j] 交换一下主体可得

c[i]=j|ia[j]njd=1[dj|i] 因为j’|i,d*j’|i,所以 d|nj

设f[i]表示i的约数个数,

则有 c[i]=j|ia[j]f[nj]

f可以线筛,而然后呢?c要怎么算啊???
可以想到很多n√n的算法(比如定期重构)然而,并不能过。

注意条件:x随机

也就是说,暴力的期望复杂度为O(n log n)
还有,读入优化要很fast才行。
然后。。。就没有然后了。。。

代码

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cctype>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=1000000+5;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
int i,j,n,c[maxn/3],q,f[maxn],g[maxn];
ll a[maxn];
bool bz[maxn];
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;char c=Getchar();
    for(;!isdigit(c);c=Getchar());
    for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
    return x;
}
int main(){
    n=read(),q=read();
    f[1]=1;
    fo(i,2,n){
        if (!bz[i]) c[++c[0]]=i,f[i]=2,g[i]=1;
        fo(j,1,c[0]){
            if (i>n/c[j]) break;
            bz[i*c[j]]=1;
            if (i%c[j]==0) {
                g[i*c[j]]=g[i]+1;
                f[i*c[j]]=f[i]/(g[i]+1)*(g[i*c[j]]+1);
                break;
            }
            f[i*c[j]]=f[i]*2;g[i*c[j]]=1;
        }
    }
    fo(i,1,q){
        int o,x,y;
        o=read(),x=read();
        if (o==1) {
            y=read();
            fo(j,1,n/x) a[x*j]=a[x*j]+(ll)y*f[j];
        }else printf("%lld\n",a[x]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值