hdu4407容斥原理

题意:
有一个元素为 1~n 的数列{An},有2种操作(1000次):
1、求某段区间 [a,b] 中与 p 互质的数的和。
2、将数列中某个位置元素的值改变。

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {

    public static void main(String[] args) throws IOException{
           StreamTokenizer cin = new StreamTokenizer(new BufferedInputStream(System.in)); 
           InputReader in = new InputReader(System.in)  ;
           PrintWriter out = new PrintWriter(System.out) ;

           int t = in.nextInt() ;
           for(int i = 1 ; i <= t ; i++){
                new Task().solve(in, out)  ;  // out.flush() ;
           }
           out.flush() ; 
    }

}


class  Task{

       static int N = 700 ;
       static int[] prime = new int[N] ;
       static int pid = 0 ;
       static boolean[] vis = new boolean[N] ;
       static{
             for(int i = 2 ; i < N ; i++){
                  if(! vis[i]) prime[pid++] = i ;
                  for(int j = 0 ; j < pid && prime[j] * i < N ; j++){
                          vis[i * prime[j]] = true ;
                          if(i % prime[j] == 0) break ;
                  }
             }
       }

       int  gcd(int x , int y){
            return y == 0 ? x : gcd(y , x%y) ; 
       }

       HashMap<Integer, Integer> hash = new HashMap<Integer, Integer>() ;
       ArrayList<Integer> factor = new ArrayList<Integer>() ;

       long  sigma(long n){
             return (n + 1 ) * n / 2 ;
       }

       long  sum(int n){
             long ans = sigma(n) ;
             int m = factor.size() ;
             int limit = 1<<m ;
             for(int i = 1 ; i < limit ; i++){
                  int k = 0 ;
                  int val = 1 ;
                  for(int j = 0 ; j < m ; j++){
                       if((i & (1<<j)) > 0){
                            k++ ;
                            val *= factor.get(j)  ;
                       }
                  }
                  long t = sigma(n/val) * val ;
                  if((k&1) > 0) ans -= t ;
                  else ans += t ;
             }
             return ans ;
       }

       long  ask(int left , int right , int p){    
             int n = p ;
             factor.clear();
             for(int i = 0 ; i < pid && prime[i]*prime[i] <= n ; i++){
                   if(n % prime[i] == 0){
                        while(n % prime[i] == 0) n /= prime[i] ;
                        factor.add(prime[i]) ;
                   }
             }
             if(n != 1) factor.add(n) ;

             long ans = sum(right) - sum(left-1) ;

             for(Map.Entry<Integer, Integer> e : hash.entrySet()){
                   int id = e.getKey() ;
                   int val = e.getValue() ;
                   if(left <= id && id <= right){
                         if(gcd(id , p) == 1) ans -= id ;
                         if(gcd(val ,p) == 1) ans += val ;
                   }
             }

             return ans ;
       }

       public void solve(InputReader in , PrintWriter out) throws IOException{
              int n = in.nextInt() ;
              int m = in.nextInt() ;
              while(m-- > 0){
                    if(in.nextInt() == 1) 
                        out.println(ask(in.nextInt() , in.nextInt() , in.nextInt())) ;
                    else  hash.put(in.nextInt(), in.nextInt()) ;
              }
       }
}

class   InputReader{
        public BufferedReader  reader;
        public StringTokenizer  tokenizer;

        public InputReader(InputStream stream){
               reader = new BufferedReader(new InputStreamReader(stream), 32768) ;
               tokenizer = null ;
        }

        public String next(){
               while(tokenizer == null || ! tokenizer.hasMoreTokens()){
                   try{
                        tokenizer = new StringTokenizer(reader.readLine());
                   }catch (IOException e){
                        throw new RuntimeException(e);
                   }
               }
               return tokenizer.nextToken();  
        }

        public int  nextInt(){
               return Integer.parseInt(next());
        }

        public long nextLong(){
               return Long.parseLong(next());
        }

        public double nextDouble(){
               return  Double.parseDouble(next());
        }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值