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
1/p看做从1~n中某数有n的因子p的概率,则1-1/p是没有因子p的概率,最前面的n是指1~n的数的个数,由乘法公式可见F的意义
此题设函数F(n,m)为公因子为1的排列的个数,易见当m为质数时
普遍看,总排列个数为,取p|m,则1/p为1~m的某数有因子p的概率,为前n个数都有p因子的概率,即这n+1个数有公因子p的概率
所以由乘法公式见:
这位大牛的解释真的很犀利啊,原本不大清楚欧拉函数具体的意思,这下子大牛把欧拉函数拓展了~~~对欧拉函数的理解深刻了好多,膜拜!
这题我是用高精度写的,好像用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; }