zoukankan      html  css  js  c++  java
  • bzoj2154(莫比乌斯反演)

    又是一道经典题.

    1.学习了下O(n) 的做法。

    //
    //  main.cpp
    //  bzoj2154
    //
    //  Created by New_Life on 16/7/7.
    //  Copyright © 2016年 chenhuan001. All rights reserved.
    //
    
    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    using namespace std;
    
    #define N 10001000
    #define MOD 20101009
    
    //--莫比乌斯反演函数--//
    //说明:利用线性素数筛选顺便求了个mu
    //注释部分为求从区间[1,b]和区间[1,d]中取两个数,互质对数O(n^0.5)
    //复杂度:O(n)
    int mu[N];
    long long sum[N];
    int prime[N];
    bool mark[N];
    
    void mobus()
    {
        int pcnt=0;
        memset(mark,0,sizeof(mark));
        mu[1] = 1;
        for(int i=2;i<N;i++)
        {
            if(mark[i] == 0)
            {
                prime[pcnt++] = i;
                mu[i] = -1;
            }
            for(int j=0;j<pcnt && i*prime[j]<N;j++)
            {
                int tmp = i*prime[j];
                mark[tmp] = 1;
                if( i%prime[j] == 0 )
                {
                    mu[tmp] = 0;
                    break;
                }
                
                mu[tmp] = mu[i]*-1;
            }
        }
        for(int i=1;i<N;i++)
        {
            sum[i] += sum[i-1]+(long long)mu[i]*i*i;
            sum[i] %= MOD;
        }
    }
    
    
    
    long long gaobili(long long b,long long d)
    {
        if(b<=0||d<=0) return 0;
        long long m = min(b,d);
        long long ans = 0;
        while(m>=1)
        {
            long long tb = b/( b/m +1 )+1;
            long long td = d/( d/m +1 )+1;
            //前进的最大位置
            long long tm = max(tb,td);
            ans += (sum[m]-sum[tm-1])*(((b/m+1)*(b/m)/2)%MOD)%MOD*(((d/m+1)*(d/m)/2)%MOD)%MOD ;
            ans %= MOD;
            m = tm-1;
        }
        return ans;
    }
    //等差数列求和模板,[a1,a1+d,...,an]
    long long allsum(long long a1,long long an,long long n)
    {
        if(n%2==0)
            return (a1+an)*(n/2);
        else return ((a1+an)/2)*n;
    }
    
    int main(int argc, const char * argv[]) {
        mobus();
        int b,d;
        while(scanf("%d%d",&b,&d)!=EOF)
        {
            int m = min(b,d);
            long long ans = 0;
            while(m>=1)
            {
                int tb = b/( b/m +1 )+1;
                int td = d/( d/m +1 )+1;
                //前进的最大位置
                int tm = max(tb,td);
                ans += allsum(tm,m,m-tm+1)%MOD*gaobili(b/m, d/m)%MOD;
                ans %= MOD;
                m = tm-1;
            }
            cout<<(ans+MOD)%MOD<<endl;
        }
        return 0;
    }
    /*
     4 5
     
     */

    2.O(n)预处理,每次查询n^0.5

    因为bzoj2693题目找不到了,所以直接用了这题来测试。

    这题首先是一个经典的公式变形。 交换连加时变量的位置。

    而根据第二个重要的性质,乘性函数的乘除之后还是乘性函数。(加减并不是)

    所以后面的连加部分也是乘性函数,这时只需要的单独看只含一个因子的时候,因为里面含有u(i),所以对于D=x^k(x是素因子)只有当i = 1 或 x 时不为0,所以

    后面的为x^k(1-x)。这时可以在线性筛选时顺便求出来。

    **************************************************************
        Problem: 2154
        User: chenhuan001
        Language: C++
        Result: Accepted
        Time:16668 ms
        Memory:93088 kb
    ****************************************************************/
     
      
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    //--莫比乌斯反演函数--//
    //说明:利用线性素数筛选顺便求了个mu
    //注释部分为求从区间[1,b]和区间[1,d]中取两个数,互质对数O(n^0.5)
    //复杂度:O(n)
    #define N 10000010
    bool mark[N];
    int prime[N/10];
         
    long long sum[N];
      
    #define MOD 20101009
      
    void mobus()
    {
        int pcnt=0;
         
        sum[1] = 1;
        for(int i=2;i<N;i++)
        {
            if(mark[i] == 0)
            {
                prime[pcnt++] = i;
                 
                sum[i] = (long long)i*(1-i)%MOD;
            }
            for(int j=0;j<pcnt && i*prime[j]<N;j++)
            {
                int tmp = i*prime[j];
                mark[tmp] = 1;
                if( i%prime[j] == 0 )
                {
                    sum[tmp] = sum[i]*prime[j];
                    sum[tmp] %= MOD;
                
                    break;
                }
                else
                {
                    sum[tmp] = sum[i]*(sum[prime[j]])%MOD;
                }
                  
                
            }
        }
        for(int i=1;i<N;i++)
            sum[i] = (sum[i]+sum[i-1])%MOD;
    }
      
    long long gaobili(int b,int d)
    {
        if(b<=0||d<=0) return 0;
        long long m = min(b,d);
        long long ans = 0;
        while(m>=1)
        {
            long long tb = b/( b/m +1 )+1;
            long long td = d/( d/m +1 )+1;
            //前进的最大位置
            long long tm = max(tb,td);
            ans += (sum[m]-sum[tm-1])*(((b/m+1)*(b/m)/2)%MOD)%MOD*(((d/m+1)*(d/m)/2)%MOD)%MOD;
            ans %= MOD;
            m = tm-1;
        }
        return (ans+MOD)%MOD;
    }    
      
    int main()
    {
        mobus();
        int b,d;
        while(scanf("%d%d",&b,&d)!=EOF)
        {
            printf("%d
    ",(int)gaobili(b,d));
        }
        return 0;
    }

    至此mobus大概都刷了一遍,原以为很复杂的东西,其实也不是很难。以后面对的题目可能有更多的公式变形,或许难在找出莫比乌斯模型。但基本的也就是这些方法了。

    治好了多年的公式恐惧症。。

  • 相关阅读:
    MCU开发之I2C通信
    hibernate特殊的映射
    Hibernate使用
    css设置让a标签充满整个li
    margin
    border属性
    列表
    链接样式
    相机内参外参
    tmux
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5648631.html
Copyright © 2011-2022 走看看