BZOJ #3853. GCD Array

给你一个序列,支持两个操作:

  1. n , d , v , a [ i ] + = [ ( i , n ) = d ] v n,d,v,a[i]+=[(i,n)=d]*v
  2. 求a的前缀和.

a [ i ] + = [ ( i , n ) = d ] v = [ ( i / d , n / d ) = 1 ] v = k ( i / d ) , k ( n / d ) μ ( k ) v a[i]+=[(i,n)=d]*v=[(i/d,n/d)=1]*v=\sum_{k|(i/d),k|(n/d)} \mu(k)v

此时设 a [ i ] = j i f [ j ] a[i]=\sum_{j|i} f[j] .
则我们需要 f [ d k ] + = μ ( k ) v ( k ( n / d ) ) f[dk]+=\mu(k)*v(k|(n/d)) .

求和的时候, i = 1 n a [ i ] = i = 1 n j i f [ j ] = d = 1 n f ( d ) f l o o r ( n / d ) . \sum_{i=1}^n a[i]=\sum_{i=1}^n \sum_{j|i} f[j]=\sum_{d=1}^n f(d)*floor(n/d).

此时树状数组优化一下,单次复杂度 O ( n l o g n ) O(\sqrt n log n) .

#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=2e5+10,size=1<<20,mod=998244353;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

int n,m,mu[N],prime[N],tot; bool v[N];
ll c[N];
void add(int x,int y) {for(	;x<=n;x+=x&-x) c[x]+=y;}
ll sum(int x) {ll y=0; for(	;x;x-=x&-x) y+=c[x]; return y;}
struct edge{int d,next;} a[N*20];int len,last[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]}; last[x]=len;} 

int main() {
	for(int i=1;i<N;i++)
		for(int j=i;j<N;j+=i)
			ins(j,i);
	mu[1]=1;
	for(int i=2;i<N;i++) {
		if(!v[i]) prime[++tot]=i,mu[i]=-1;
		for(int j=1,k;(k=prime[j]*i)<N;j++) {
			v[k]=1;
			if(i%prime[j]==0) break;
			mu[k]=-mu[i];
		}
	}
	int T=0;
	while(1) {
		qr(n); qr(m);
		if(!n) break;
		printf("Case #%d:\n",++T);
		for(int i=1;i<=n;i++) c[i]=0;
		int op,x,y,z;
		while(m--) {
			qr(op); qr(x);
			if(op==1) {
				qr(y); qr(z);
				if(x%y==0) for(int k=last[x/y];k;k=a[k].next) add(y*a[k].d,mu[a[k].d]*z);
			}
			else {
				ll ans=0;
				for(int l=1,r;l<=x;l=++r) {
					r=x/(x/l);
					ans+=(ll)(x/l)*(sum(r)-sum(l-1));
				}
				pr2(ans);
			}
		}
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/107566021