1. 程式人生 > >hdu 4407 容斥原理

hdu 4407 容斥原理

Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1726    Accepted Submission(s): 486


Problem Description XXX is puzzled with the question below:

1, 2, 3, ..., n (1<=n<=400000) are placed in a line. There are m (1<=m<=1000) operations of two kinds.

Operation 1: among the x-th number to the y-th number (inclusive), get the sum of the numbers which are co-prime with p( 1 <=p <= 400000).
Operation 2: change the x-th number to c( 1 <=c <= 400000).

For each operation, XXX will spend a lot of time to treat it. So he wants to ask you to help him.

Input There are several test cases.
The first line in the input is an integer indicating the number of test cases.
For each case, the first line begins with two integers --- the above mentioned n and m.
Each the following m lines contains an operation.
Operation 1 is in this format: "1 x y p".
Operation 2 is in this format: "2 x c".
Output For each operation 1, output a single integer in one line representing the result.

Sample Input 1 3 3 2 2 3 1 1 3 4 1 2 3 6
Sample Output 7 0
Source

一開始是1-400000的序列,兩種操作,一種是把第x個數改為y,另一種是計算從第x個數開始,到第y個數所有數裡與p互素的元素的和。

由於序列很長,修改非常少,只有1000次,可以把修改的位置儲存下來,對區間用容斥原理計算,然後再根據修改過的數,進行單點處理,從而得到答案。

程式碼:

/* ***********************************************
Author :rabbit
Created Time :2014/4/2 14:21:05
File Name :13.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef __int64 ll;
bool isprime[1001000];
ll prime[1001000],factor[1010];
void getprime(){
    memset(isprime,1,sizeof(isprime));isprime[1]=0;
    ll &cnt=prime[0];cnt=0;
    for(ll i=2;i<=1000000;i++){
        if(isprime[i])prime[++cnt]=i;
        for(ll j=1;j<=cnt&&i*prime[j]<=1000000;j++){
            isprime[i*prime[j]]=0;
            if(i%prime[j]==0)break;
        }
    }
//    cout<<prime[0]<<endl;
}
void getfactor(ll x){
    ll &cnt=factor[1000];cnt=0;
    for(ll i=1;i<=prime[0]&&prime[i]*prime[i]<=x;i++)
        if(x%prime[i]==0){
            factor[cnt++]=prime[i];
            while(x%prime[i]==0)x/=prime[i];
        }
    if(x>1)factor[cnt++]=x;
}
ll sum[500100];
ll cal(ll x){
    ll cnt=factor[1000],ans=0;
    for(ll i=1;i<(1<<cnt);i++){
        ll pp=1,ss=0;
        for(ll j=0;j<cnt;j++)
            if(i&(1<<j)){
                ss++;pp*=factor[j];
            }
		ll d=x/pp;
		d=d*(d+1)*pp/2;
        if(ss%2)ans+=d;
        else ans-=d;
    }
    return sum[x]-ans;
}
ll gcd(ll x,ll y){
	if(x==0)return y;
	return gcd(y%x,x);
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     getprime();
     int T;
	 sum[1]=1;for(ll i=2;i<=400000;i++)sum[i]=sum[i-1]+i;
     scanf("%d",&T);
     while(T--){
        ll N,M;
		scanf("%I64d%I64d",&N,&M);
		ll x,y,p,op;
		ll ans=0;
		map<ll,ll> mp;
		map<ll,ll>::iterator it;
		//getfactor(3);cout<<cal(3)<<endl;
		while(M--){
			scanf("%I64d",&op);
			if(op==2){
				scanf("%I64d%I64d",&x,&y);
				mp[x]=y;
			}
			else{
				scanf("%I64d%I64d%I64d",&x,&y,&p);
				getfactor(p);
				ll ans=cal(y)-cal(x-1);
				for(it=mp.begin();it!=mp.end();it++)
					if(it->first>=x&&it->first<=y){
						if(gcd(it->first,p)==1)ans-=it->first;
						if(gcd(it->second,p)==1)ans+=it->second;
					}
				cout<<ans<<endl;
			}
		}
	//	for(it=mp.begin();it!=mp.end();it++)cout<<it->first<<" "<<(*it).second<<endl;
     }
     return 0;
}