POJ 1091 跳蚤 扩展欧拉函数 or 容斥原理

POJ 1091  好题!

题意:要使得gcd(a1,a2,a3...,an,m) = 1 (1<=a[x] <= m) 


容斥原理:首先预处理出m所有的素因子,组合总数就是m^n,P(x) 表示由x个素因子乘积得到的数为gcd的

总的组合数,所以由容斥原理可知ans = m^n - P(1) + P(2) - P(3) + ...


扩展欧拉函数 : 参考自http://scturtle.is-programmer.com/posts/19402.html

欧拉函数F(n)=n \prod_{p|n}(1-\frac{1}{p})的概率解释:

1/p看做从1~n中某数有n的因子p的概率,则1-1/p是没有因子p的概率,最前面的n是指1~n的数的个数,由乘法公式可见F的意义

此题设函数F(n,m)为公因子为1的排列的个数,易见当m为质数时 F(n,m)=m^n-1

普遍看,总排列个数为m^n,取p|m,则1/p为1~m的某数有因子p的概率,1/{p^n}为前n个数都有p因子的概率,即这n+1个数有公因子p的概率

所以由乘法公式见:

F(n,m)=m^n\prod_{p|n}(1-\frac{1}{p^n})


这位大牛的解释真的很犀利啊,原本不大清楚欧拉函数具体的意思,这下子大牛把欧拉函数拓展了~~~对欧拉函数的理解深刻了好多,膜拜!


这题我是用高精度写的,好像用long long也能过,是因为数据太弱了,其实必须要用高精度了。。。我还是不改成long long了


容斥原理

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std ;
 
const int maxn = 200 ;
char s1[maxn] , s2[maxn] , s3[maxn] ;
int max ( int a , int b ) { return a > b ? a : b ; }
 
struct bign
{
    short s[maxn] , len ;
    bign () { memset ( s ,0 , sizeof ( s ) ) ; len = 1 ; }
    bign operator = ( const char *num)
    {
        len = strlen ( num ) ;
        for ( int i = 0 ; i < len ; i ++ ) s[i] = num[len-i-1] - '0' ;
        return *this ;
    }
    bool operator < ( const bign &b ) const
    {
        if ( len != b.len ) return len < b.len ;
        for ( int i = len - 1 ; i >= 0 ; i -- )
            if ( s[i] != b.s[i] ) return s[i] < b.s[i] ;
        return false ;
    }
    bool operator > ( const bign &b ) const { return b < *this ; }
    bool operator <= ( const bign &b ) const { return !( b < *this ) ; }
    bool operator >= ( const bign &b ) const { return !( *this < b ) ; }
    bool operator != ( const bign &b ) const { return ( *this < b ) || ( b < *this ) ; }
    bool operator == ( const bign &b ) const { return !( *this < b ) && !( b < *this ) ; }
    bign operator = ( int num )
    {
        char s[maxn] ;
        sprintf ( s , "%d" , num ) ;
        *this = s ;
        return *this ;
    }
    bign ( const char *num ) { *this = num ; }
    bign ( int num ) { *this = num ; }
    string str () const
    {
        string res ;
        res = "" ;
        for ( int i = 0 ; i < len ; i ++ ) res = ( char ) ( s[i] + '0' ) + res ;
        if ( res == "" ) res = '0' ;
        return res ;
    }
    bign operator + ( const bign& b ) const
    {
        bign c ;
        c.len = 0 ;
        for ( int i = 0 , g = 0 ; g || i < max ( len , b.len ) ; i ++ )
        {
            int x = g ;
            if ( i < len ) x += s[i] ;
            if ( i < b.len ) x += b.s[i] ;
            c.s[c.len++] = x % 10 ;
            g = x / 10 ;
        }
        return c ;
    }
    bign operator += ( const bign& b )
    {
        *this = *this + b ;
        return *this ;
    }
    bign operator - ( const bign& b ) const
    {
        bign t1 , t2 ;
        bign t3 ;
        t3.len = 0 ;
        if ( *this < b ) t1 = b , t2 = *this  ;
        else t1 = *this , t2 = b ;
        for ( int i = 0 ; i < t2.len ; i ++ )
        {
            int g = t1.s[i] - t2.s[i] ;
            if ( g < 0 )
            {
                g += 10 ;
                int j = i ;
                while ( t1.s[j+1] == 0 ) t1.s[j+1] = 9 , j ++ ;
                t1.s[j+1] -- ;
            }
            t3.s[t3.len++] = g ;
        }
        for ( int i = t2.len ; i < t1.len ; i ++ ) t3.s[t3.len++] = t1.s[i] ;
        for ( int i = t3.len - 1 ; i >= 0 ; i -- )
            if ( t3.s[i] == 0 ) t3.len -- ;
            else break ;
        return t3 ;
    }
    bign operator -= ( const bign& b )
    {
        *this = *this - b ;
        return *this ;
    }
    bign operator * ( const bign& b ) const
    {
        bign d ;
        d.len = 0 ;
        for ( int i = 0 ; i < len ; i ++ )
        {
            bign c ;
            c.len = 0 ;
            for ( int k = 0 ; k < i ; k ++ )
                c.s[c.len++] = 0 ;
            for ( int j = 0 , g = 0 ; g || j < b.len ; j ++ )
            {
                if ( j < b.len ) g += s[i]* b.s[j];
                c.s[c.len++] = g % 10 ;
                g = g/10 ;
            }
            d += c ;
        }
        for ( int i = d.len - 1 ; i >= 0 ; i -- )
            if ( d.s[i] == 0 ) d.len -- ;
            else break ;
        if ( d.len == 0 ) d = 0 ;
        return d ;
    }
    bign operator *= ( const bign &b )
    {
        *this = *this * b ;
        return *this ;
    }
    bign operator / ( const bign &b ) const
    {
        if ( *this < b ) return 0 ;
        bign t1 = *this ;
        bign t2 = b ;
        bign c = 10 ;
        bign ans ;
        ans.len = 0 ;
        int j ;
        while ( t1 > t2 )
        {
            bign t3 ; t3 = 0 ;
            for ( int i = t1.len - 1 ; i >= 0 ; i -- )
            {
                t3 *= c ; t3.s[0] = t1.s[i] ;
                if ( t3 >= t2 ) { j = i ; break ; }
            }
            bign x , y , z ;
            for ( int i = 1 ; i <= 9 ; i ++ )
            {
                x = i ;
                y = i + 1 ;
                if ( t2 * i <= t3 && t2 * y > t3 )
                {
                    ans.s[ans.len++] = i ;
                    break ;
                }
            }
            z = t2 * x ;
            z = t3 - z ;
            while ( z < t2 && j > 0 )
            {
                z *= c ;
                z.s[0] = t1.s[--j] ;
                if ( z < t2 )
                ans.s[ans.len++] = 0 ;
            }
            if ( j >= 0 )
            {
                y.len = 0 ;
                for ( int i = 0 ; i < j ; i ++ )
                {
                    z *= c ;
                    y.s[y.len++] = t1.s[i] ;
                }
                z += y ;
            }
            t1 = z ;
        }
        reverse ( ans.s , ans.s + ans.len ) ;
        return ans ;
    }
};
 
istream& operator >> ( istream &in , bign& x )
{
    string s ;
    in >> s ;
    x = s.c_str() ;
    return in ;
}
 
ostream& operator << ( ostream &out , const bign &x )
{
    out << x.str() ;
    return out ;
}

int f[111],d[111], m ,n, top; // top 表示总的素因子数
bign temp , change;
void rongchi(int now,int num,int tot) // now 当前处理到的素因子  num 已经有的素因子数  tot表示总共需要的素因子数
{
	int i;
	if(num == tot)
	{
		int nn = m;
		for(i = 0;i < tot; i++)
			nn = nn/d[i];
		bign mm = nn;
		for(i = 0;i < n-1 ;i++)
			mm = mm*nn;
		change = change+mm;
	}
	else
		for(i = now;i < top ;i++)
		{
			d[num] = f[i];
			rongchi(i+1,num+1,tot);
		}
}
int main()
{
	int i;
	int tot = 0;
	scanf("%d%d",&n,&m);
	int cur = m;
	for(i = 2;i*i <= m ;i ++)
		if(m%i == 0)
		{
			f[tot++] = i; //  处理出素因子
			while(m%i==0)
				m /= i;
		}
	if(m != 1)
		f[tot++] = m;
	top = tot;
	m = cur;
	bign ans = m;
	for(i = 0;i < n-1; i++)
		ans = ans*m;
	temp = ans;
	for(i = 0;i < top; i++)  // 就是筛选素因子   其实就可以直接二进制压缩状态来做,以前做的就不改了
	{
		change = 0;
		rongchi(0,0,i+1);
		if(i&1)
			ans = ans+change;
		else
			ans = ans-change;
	}
	cout<<ans<<endl;
}

扩展欧拉函数

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std ;
 
const int maxn = 200 ;
char s1[maxn] , s2[maxn] , s3[maxn] ;
int max ( int a , int b ) { return a > b ? a : b ; }
 
struct bign
{
    short s[maxn] , len ;
    bign () { memset ( s ,0 , sizeof ( s ) ) ; len = 1 ; }
    bign operator = ( const char *num)
    {
        len = strlen ( num ) ;
        for ( int i = 0 ; i < len ; i ++ ) s[i] = num[len-i-1] - '0' ;
        return *this ;
    }
    bool operator < ( const bign &b ) const
    {
        if ( len != b.len ) return len < b.len ;
        for ( int i = len - 1 ; i >= 0 ; i -- )
            if ( s[i] != b.s[i] ) return s[i] < b.s[i] ;
        return false ;
    }
    bool operator > ( const bign &b ) const { return b < *this ; }
    bool operator <= ( const bign &b ) const { return !( b < *this ) ; }
    bool operator >= ( const bign &b ) const { return !( *this < b ) ; }
    bool operator != ( const bign &b ) const { return ( *this < b ) || ( b < *this ) ; }
    bool operator == ( const bign &b ) const { return !( *this < b ) && !( b < *this ) ; }
    bign operator = ( int num )
    {
        char s[maxn] ;
        sprintf ( s , "%d" , num ) ;
        *this = s ;
        return *this ;
    }
    bign ( const char *num ) { *this = num ; }
    bign ( int num ) { *this = num ; }
    string str () const
    {
        string res ;
        res = "" ;
        for ( int i = 0 ; i < len ; i ++ ) res = ( char ) ( s[i] + '0' ) + res ;
        if ( res == "" ) res = '0' ;
        return res ;
    }
    bign operator + ( const bign& b ) const
    {
        bign c ;
        c.len = 0 ;
        for ( int i = 0 , g = 0 ; g || i < max ( len , b.len ) ; i ++ )
        {
            int x = g ;
            if ( i < len ) x += s[i] ;
            if ( i < b.len ) x += b.s[i] ;
            c.s[c.len++] = x % 10 ;
            g = x / 10 ;
        }
        return c ;
    }
    bign operator += ( const bign& b )
    {
        *this = *this + b ;
        return *this ;
    }
    bign operator - ( const bign& b ) const
    {
        bign t1 , t2 ;
        bign t3 ;
        t3.len = 0 ;
        if ( *this < b ) t1 = b , t2 = *this  ;
        else t1 = *this , t2 = b ;
        for ( int i = 0 ; i < t2.len ; i ++ )
        {
            int g = t1.s[i] - t2.s[i] ;
            if ( g < 0 )
            {
                g += 10 ;
                int j = i ;
                while ( t1.s[j+1] == 0 ) t1.s[j+1] = 9 , j ++ ;
                t1.s[j+1] -- ;
            }
            t3.s[t3.len++] = g ;
        }
        for ( int i = t2.len ; i < t1.len ; i ++ ) t3.s[t3.len++] = t1.s[i] ;
        for ( int i = t3.len - 1 ; i >= 0 ; i -- )
            if ( t3.s[i] == 0 ) t3.len -- ;
            else break ;
        return t3 ;
    }
    bign operator -= ( const bign& b )
    {
        *this = *this - b ;
        return *this ;
    }
    bign operator * ( const bign& b ) const
    {
        bign d ;
        d.len = 0 ;
        for ( int i = 0 ; i < len ; i ++ )
        {
            bign c ;
            c.len = 0 ;
            for ( int k = 0 ; k < i ; k ++ )
                c.s[c.len++] = 0 ;
            for ( int j = 0 , g = 0 ; g || j < b.len ; j ++ )
            {
                if ( j < b.len ) g += s[i]* b.s[j];
                c.s[c.len++] = g % 10 ;
                g = g/10 ;
            }
            d += c ;
        }
        for ( int i = d.len - 1 ; i >= 0 ; i -- )
            if ( d.s[i] == 0 ) d.len -- ;
            else break ;
        if ( d.len == 0 ) d = 0 ;
        return d ;
    }
    bign operator *= ( const bign &b )
    {
        *this = *this * b ;
        return *this ;
    }
    bign operator / ( const bign &b ) const
    {
        if ( *this < b ) return 0 ;
        bign t1 = *this ;
        bign t2 = b ;
        bign c = 10 ;
        bign ans ;
        ans.len = 0 ;
        int j ;
        while ( t1 > t2 )
        {
            bign t3 ; t3 = 0 ;
            for ( int i = t1.len - 1 ; i >= 0 ; i -- )
            {
                t3 *= c ; t3.s[0] = t1.s[i] ;
                if ( t3 >= t2 ) { j = i ; break ; }
            }
            bign x , y , z ;
            for ( int i = 1 ; i <= 9 ; i ++ )
            {
                x = i ;
                y = i + 1 ;
                if ( t2 * i <= t3 && t2 * y > t3 )
                {
                    ans.s[ans.len++] = i ;
                    break ;
                }
            }
            z = t2 * x ;
            z = t3 - z ;
            while ( z < t2 && j > 0 )
            {
                z *= c ;
                z.s[0] = t1.s[--j] ;
                if ( z < t2 )
                ans.s[ans.len++] = 0 ;
            }
            if ( j >= 0 )
            {
                y.len = 0 ;
                for ( int i = 0 ; i < j ; i ++ )
                {
                    z *= c ;
                    y.s[y.len++] = t1.s[i] ;
                }
                z += y ;
            }
            t1 = z ;
        }
        reverse ( ans.s , ans.s + ans.len ) ;
        return ans ;
    }
};
 
istream& operator >> ( istream &in , bign& x )
{
    string s ;
    in >> s ;
    x = s.c_str() ;
    return in ;
}
 
ostream& operator << ( ostream &out , const bign &x )
{
    out << x.str() ;
    return out ;
}
 
int f[11111];
int main()
{
	int n,m,i;
	int tot = 0;
	scanf("%d%d",&n,&m);
	int cur = m;
	for(i = 2;i*i <= m ;i ++)
		if(m%i == 0)
		{
			f[tot++] = i;
			while(m%i==0)
				m /= i;
		}
	if(m != 1)
		f[tot++] = m;
	m = cur;
	bign ans = m;
	for(i = 0;i < n-1; i++)
		ans = ans*m;
	//cout<<ans<<endl;
	for(i = 0;i < tot; i++)
	{
		
		bign d = f[i];
		for(int j = 0;j < n-1; j++)
			d = d*f[i];
		ans = ans*(d-1);
		ans = ans/d;
	}
	cout<<ans<<endl;
}

你可能感兴趣的:(数论,poj,容斥原理)