bzoj 3853 GCD Array

3853: GCD Array

Time Limit: 6 Sec   Memory Limit: 64 MB
Submit: 341   Solved: 130
[ Submit][ Status][ Discuss]

Description

Teacher Mai finds that many problems about arithmetic function can be reduced to the following problem:
Maintain an array a with index from 1 to l. There are two kinds of operations:
  1. Add v to ax for every x that gcd(x,n)=d.
  2. Query Sigma(Xi) (i<=1<=X)

   
   

Input

There are multiple test cases, terminated by a line "0 0".
For each test case, the first line contains two integers l,Q(1<=l,Q<=5*10^4), indicating the length of the array and the number of the operations.
In following Q lines, each line indicates an operation, and the format is "1 n d v" or "2 x" (1<=n,d,v<=2*10^5,1<=x<=l).

Output

For each case, output "Case #k:" first, where k is the case number counting from 1.
Then output the answer to each query.

Sample Input

6 4
1 4 1 2
2 5
1 3 3 3
2 3
0 0

Sample Output

Case #1:
6
7

HINT

Source

By 镇海中学





【分析】
脑洞莫比乌斯反演
公式写不动,给一个链  http://www.cnblogs.com/SilverNebula/p/6991328.html
样例没过就交我也是醉了QAQ



【代码】
//bzoj 3853 GCD Array
#include<bits/stdc++.h>
#define N 200000
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=200005;
vector <int> f[mxn];
int n,m,Q,T,x,d,v;
bool vis[mxn];
int pri[mxn],mu[mxn];
ll c[mxn];
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x;
}
inline int lowbit(int x) {return x&-x;}
inline void add(int u,ll v)
{
	for(int i=u;i<=n;i+=lowbit(i)) c[i]+=v;
}
inline ll getsum(int u)
{
	ll sum=0;
	for(int i=u;i>=1;i-=lowbit(i))
	  sum+=c[i];
	return sum;
}
inline void init()
{
	int i,j;
	mu[1]=1;
	fo(i,2,N) 
	{
		if(!vis[i]) pri[++pri[0]]=i,mu[i]=-1;
		for(j=1;j<=pri[0]&&(ll)i*pri[j]<=N;j++)
		{
			vis[i*pri[j]]=1;
			if(i%pri[j]==0) break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	fo(i,1,N)
	  for(j=i;j<=N;j+=i)
	    f[j].push_back(i);
}
inline ll solve(int x)
{
	ll ans=0;
	for(int i=1,last=0;i<=x;i=last+1)
	{
		last=x/(x/i);
		ans+=(getsum(last)-getsum(i-1))*(x/i);
	}
	return ans;
}
int main()
{
	init();
	int i,j,k,opt;
	while(n=read(),m=read())
	{
		if(!n && !m) return 0;
		memset(c,0,sizeof c);
		printf("Case #%d:\n",++T);
		while(m--)
		{
			opt=read();
			if(opt==1)
			{
				x=read(),d=read(),v=read();
				if(x%d!=0) continue;k=x/d;
				for(i=0;i<f[k].size();i++)
				  add((ll)f[k][i]*d,(ll)v*mu[f[k][i]]);
			}
			else
			{
				x=read();
				printf("%lld\n",solve(x));
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值