容斥原理
直接复制别人的题解,代码自己写的,被pow的精度坑了,要+eps。。题意:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。
我们可以由n^(1/p),知道指数为p的有多少个数。
通过观察,可以发现若一个数可以表示成x^(k*t),则可以表示成(x^k)^t。因此指数必然为素数。
枚举素数便可以得到指数为p的个数,但是可能出现重复,例如:x^3=y^5,其中x=t^5,y=t^3。
运用容斥原理,设a[i]表示指数为第i个素数的个数,那么答案等于满足一个的,减去两个的,加上三个的……
由于2^60>10^18,2*3*5*7>60,所以只要枚举到三即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define mnx 1100 13 14 int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61 }; 15 int main(){ 16 LL n; 17 while( scanf( "%I64d", &n ) != EOF ){ 18 LL ans = 0, g = 1<<18; 19 for( int i = 1; i < g; ++i ){ 20 int cnt = 0, k = i; 21 LL base = 1; 22 for( int j = 0; j < 18; ++j ){ 23 if( k % 2 ) cnt++, base *= prime[j]; 24 k >>= 1; 25 } 26 if( cnt > 3 ) continue; 27 if( cnt % 2 ) 28 ans += (LL)( pow( n, 1.0/base) + eps ) - 1; 29 else ans -= (LL)( pow( n, 1.0/base) + eps ) - 1; 30 } 31 cout << ans + 1 << endl; 32 } 33 return 0; 34 }
HDU 1796 How many integers can you find
感觉最简单的一种容斥了。。有坑的就是n要用longlong
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define mnx 1100 13 14 int c[30], cnt; 15 bool vis[30]; 16 LL ans, n; 17 LL gcd( LL a, LL b ){ 18 return b == 0 ? a : gcd( b, a % b ); 19 } 20 LL lcm( LL a, LL b ){ 21 return a / gcd( a, b ) * b; 22 } 23 void dfs( int id, LL val, int num ){ 24 if( num % 2 ) 25 ans += (n-1) / val; 26 if( num % 2 == 0 && num != 0 ) 27 ans -= (n-1) / val; 28 for( int i = id; i < cnt; ++i ){ 29 if( lcm( val, c[i] ) < n ) 30 dfs( i+1, lcm( val, c[i] ), num+1 ); 31 } 32 } 33 int main(){ 34 int m; 35 while( scanf( "%I64d%d", &n, &m ) != EOF ){ 36 ans = 0 , cnt = 0; 37 int v; 38 memset( vis, 0, sizeof(vis) ); 39 for( int i = 0; i < m; ++i ){ 40 scanf( "%d", &v ); 41 if( !vis[v] && v ) c[cnt++] = v; 42 vis[v] = 1; 43 } 44 dfs( 0, 1, 0 ); 45 cout << ans << endl; 46 } 47 return 0; 48 }
还是直接拉题解吧。。感觉别人说的比较清晰,这里
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define mnx 100100 13 14 int fat[100], cnt; 15 void getfat( int val ){ 16 for( int i = 2; i * i <= val; ++i ){ 17 if( val % i == 0 ) 18 fat[cnt++] = i; 19 while( val % i == 0 ) 20 val /= i; 21 if( val == 1 ) break; 22 } 23 if( val > 1 ) fat[cnt++] = val; 24 } 25 LL ans, ret; 26 int n, m; 27 void dfs( int id, int val, int num ){ 28 if( num % 2 ) 29 ans += m / val; 30 if( num % 2 == 0 && num != 0 ) 31 ans -= m / val; 32 for( int i = id; i < cnt; ++i ) 33 if( val * fat[i] <= m ) 34 dfs( i+1, val * fat[i], num+1 ); 35 } 36 int main(){ 37 int cas; 38 scanf( "%d", &cas ); 39 while( cas-- ){ 40 ret = 0; 41 scanf( "%d%d", &n, &m ); 42 for( int i = 1; i <= n; ++i ){ 43 ans = 0, cnt = 0; 44 if( i == 1 || m == 1 ){ 45 ret += m; continue; 46 } 47 getfat( i ); 48 dfs( 0, 1, 0 ); 49 ret += ( m - ans ); 50 } 51 printf( "%I64d\n", ret ); 52 } 53 return 0; 54 }
HDU 1695 GCD
感觉做了上题就差不多会做这题了。。可以把 b /= k, d /= k,就跟上题差不多了,特判k==0。具体的参考kuangbin的题解吧
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define mnx 100100 13 14 int fat[100], cnt; 15 void getfat( int val ){ 16 for( int i = 2; i * i <= val; ++i ){ 17 if( val % i == 0 ) 18 fat[cnt++] = i; 19 while( val % i == 0 ) 20 val /= i; 21 if( val == 1 ) break; 22 } 23 if( val > 1 ) fat[cnt++] = val; 24 } 25 int euler[mnx]; 26 void getEuler(){ 27 memset( euler, 0, sizeof(euler) ); 28 euler[1] = 1; 29 for( int i = 2;i < mnx; i++ ) 30 if( !euler[i] ) 31 for( int j = i; j <= mnx; j += i ){ 32 if( !euler[j] ) 33 euler[j] = j; 34 euler[j] = euler[j]/i*(i-1); 35 } 36 } 37 LL ans, ret; 38 int n, nn, mm, m; 39 void dfs( int id, int val, int num ){ 40 if( num % 2 ) 41 ret += n / val; 42 if( num % 2 == 0 && num != 0 ) 43 ret -= n / val; 44 for( int i = id; i < cnt; ++i ) 45 if( val * fat[i] <= n ) 46 dfs( i+1, val * fat[i], num+1 ); 47 } 48 void calc( int v, int u ){ 49 ret = 0, cnt = 0; 50 getfat( v ); 51 dfs( 0, 1, 0 ); 52 //cout << ret << endl; 53 ans += u - ret; 54 } 55 int main(){ 56 int kk = 1, cas; 57 getEuler(); 58 scanf( "%d", &cas ); 59 while( cas-- ){ 60 ans = 0; 61 int k; 62 scanf( "%d%d%d%d%d", &nn, &n, &mm, &m, &k ); 63 if( k == 0 ){ 64 printf( "Case %d: 0\n", kk++ ); continue; 65 } 66 if( n > m ) swap( n, m ); 67 n /= k, m /= k; 68 for( int i = 1; i <= n; ++i ) 69 ans += euler[i]; 70 for( int i = n+1; i <= m; ++i ) 71 calc( i, n ); 72 printf( "Case %d: %I64d\n", kk++, ans ); 73 } 74 return 0; 75 }
类似的题型。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define mnx 100100 13 14 int n, c[20], cnt; 15 LL m, ret; 16 bool vis[20]; 17 LL gcd( LL a, LL b ){ 18 return b == 0 ? a : gcd( b, a % b ); 19 } 20 LL lcm( LL a, LL b ){ 21 return a / gcd( a, b ) * b; 22 } 23 void dfs( int id, LL val, int num ){ 24 if( num & 1 ) 25 ret += m / val; 26 if( ( num & 1 ) == 0 && num != 0 ) 27 ret -= m / val; 28 //cout << ret << endl; 29 for( int i = id; i < cnt; ++i ) 30 if( lcm( val, c[i] ) <= m ) 31 dfs( i+1, lcm(val, c[i]), num+1 ); 32 } 33 int main(){ 34 while( scanf( "%d%I64d", &n, &m ) != EOF ){ 35 memset( vis, 0, sizeof(vis) ); 36 ret = cnt = 0; 37 for( int i = 0; i < n; ++i ){ 38 int u; 39 scanf( "%d", &u ); 40 if( !vis[u] ) c[cnt++] = u; 41 vis[u] = 1; 42 } 43 dfs( 0, 1, 0 ); 44 cout << ret << endl; 45 } 46 return 0; 47 }
看cxlove的题解吧
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define mnx 510 13 14 LL low, hig; 15 LL gcd( LL a, LL b ){ 16 return b == 0 ? a : gcd( b, a % b ); 17 } 18 LL lcm( LL a, LL b ){ 19 if( a / gcd( a, b ) > hig / b ) 20 return hig + 1; 21 return a / gcd( a, b ) * b; 22 } 23 LL a[mnx], b[mnx], ans1, ans2, res, n, m; 24 void dfs( int id, LL val, int num, LL sum ){ 25 if( num & 1 ) 26 ans1 += sum / val, 27 ans2 += sum / lcm( val, res ); 28 if( (num & 1) == 0 && num ) 29 ans1 -= sum / val, 30 ans2 -= sum / lcm( val, res ); 31 for( int i = id; i < n; ++i ) 32 if( lcm( val, a[i] ) <= sum ) 33 dfs( i+1, lcm(val, a[i]), num+1, sum ); 34 } 35 int main(){ 36 while( scanf( "%d%d%lld%lld", &n, &m, &low, &hig ) != EOF ){ 37 if( n == 0 && m == 0 && low == 0 && hig == 0 ) 38 break; 39 ans1 = ans2 = 0; 40 for( int i = 0; i < n; ++i ) 41 scanf( "%lld", &a[i] ); 42 res = 1; 43 for( int i = 0; i < m; ++i ){ 44 scanf( "%lld", &b[i] ); 45 if( res > hig ){ 46 res = hig + 1; continue ; 47 } 48 res = lcm( b[i], res ); 49 } 50 dfs( 0, 1, 0, low-1 ); 51 LL ans = ans1 - ans2; 52 ans1 = ans2 = 0; 53 dfs( 0, 1, 0, hig ); 54 ans = ans1 - ans2 - ans; 55 cout << ans << endl; 56 } 57 return 0; 58 }
给你k 和 s。。问你小于等于s的数中,至少有k个数的最大公约数不等于1,问满足这样条件的数有多少组。。
3 10 有11组。。最小公约数是2的有5个数,c(5, 3) = 10,最小公约数是3的有3个,c(3, 3) = 1,共11种
组合数+容斥
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define lson l, m, rt<<1 13 #define rson m+1, r, rt<<1|1 14 #define mnx 60 15 #define inf 1000000 16 17 int prime[16] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 }; 18 int fat[mnx], cnt, ans, dp[60][60]; 19 void init(){ 20 dp[0][0] = dp[1][1] = 1; 21 for( int i = 0; i < 51; ++i ) 22 dp[i][0] = dp[i][i] = 1; 23 for( int i = 1; i < 51; ++i ) 24 for( int j = 1; j < 51; ++j ) 25 dp[i][j] = min( inf, dp[i-1][j-1] + dp[i-1][j] ); 26 27 } 28 int s, k; 29 void dfs( int id, int val, int num ){ 30 if( num & 1 ) 31 ans += dp[s/val][k]; 32 if( (num & 1) == 0 && num ) 33 ans -= dp[s/val][k]; 34 for( int i = id; i < cnt; ++i ) 35 if( val * fat[i] <= s ) 36 dfs( i+1, val * fat[i], num+1 ); 37 } 38 int main(){ 39 init(); 40 while( scanf( "%d%d", &k, &s ) != EOF ){ 41 cnt = ans = 0; 42 for( int i = 0; i < 15; ++i ){ 43 if( prime[i] * k > s ) 44 break; 45 fat[cnt++] = prime[i]; 46 } 47 dfs( 0, 1, 0 ); 48 cout << min(ans, 10000) << endl; 49 } 50 return 0; 51 }
HUST 1214 Cubic-free numbers II
给定一个区间,求不能表示成k*x*x*x(x>1)的个数。。这题数据没有给,目测要300w左右。先筛素数,然后存素数的3次方,然后就在区间内有 多少这样的素数的3次方。但是这样会重复,6^3 = 2^3 * 3^3被重复算了,就用容斥搞。注意dfs的时候 if( fat[i] * val <= sum ) dfs() 要改为 if( sum / fat[i] < val ) break;不然的话会tle
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define lson l, m, rt<<1 13 #define rson m+1, r, rt<<1|1 14 #define mnx 2010 15 16 bool prime[mnx*mnx]; 17 LL pri[mnx*mnx], cnt; 18 void init(){ 19 memset( prime, true, sizeof prime ); 20 for( int i = 2; i < 2000; ++i ){ 21 if( prime[i] ){ 22 for( int j = i * i; j <= 3000000; j += i ) 23 prime[j] = 0; 24 } 25 } 26 for( int i = 2; i <= 3000000; ++i ){ 27 if( prime[i] ){ 28 pri[cnt++] = (LL)i * (LL)i * (LL)i; 29 } 30 } 31 } 32 LL L, R, ans; 33 void dfs( int id, LL val, int num, LL sum ){ 34 if( num & 1 ) 35 ans += sum / val; 36 if( (num & 1) == 0 && num ) 37 ans -= sum / val; 38 for( int i = id; pri[i] < sum; ++i ){ 39 if( sum / pri[i] < val ) 40 break; 41 dfs( i+1, pri[i] * val, num+1, sum ); 42 } 43 } 44 int main(){ 45 int cas; 46 scanf( "%d", &cas ); 47 init(); 48 while( cas -- ){ 49 ans = 0; 50 scanf( "%lld%lld", &L, &R ); 51 LL tmp1, tmp2; 52 bool ok = 1; 53 dfs( 0, 1, 0, L-1 ); 54 tmp1 = ans, ans = 0; 55 dfs( 0, 1, 0, R-1 ); 56 tmp2 = ans; 57 printf( "%lld\n", R - L - tmp2 + tmp1 ); 58 } 59 return 0; 60 }
中文题,有n+1个卡片,且最后一张是M,其他n张都小于M,要跳到第一个单位的位置。即 a1 * x1 + a2 * x2 + ... + an * xn + M * x(n+1) = 1;方程有解的条件是
gcd( a1, a2, ..., an, M ) = 1;求出M的所有素数因子,然后用容斥求出gcd不是1的组数,用m^n( 用快速幂 ) 减去就是答案了。
按理说应该用大数或者java来做的,但是数据并没有爆long long
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> using namespace std; #define LL long long #define eps 1e-8 #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mnx 200010 LL fat[100], cnt; LL qpow( LL n, LL k ){ LL ret = 1; while( k ){ if( k & 1 ) ret *= n; n *= n; k >>= 1; } return ret; } void calc( LL m ){ for( int i = 2; i * i <= m; ++i ){ if( m % i == 0 ) fat[cnt++] = i; while( m % i == 0 ) m /= i; if( m == 1 ) break; } if( m != 1 ) fat[cnt++] = m; } LL ans, n, m; void dfs( int id, LL val, int num ){ if( num & 1 ) ans += qpow( m / val, n ); if( (num & 1) == 0 && num ) ans -= qpow( m / val, n ); for( int i = id; i < cnt; ++i ){ if( val * fat[i] > m ) break; dfs( i+1, val * fat[i], num+1 ); } } int main(){ while( scanf( "%I64d%I64d", &n, &m ) != EOF ){ ans = 0, cnt = 0; calc( m ); LL sum = qpow( m, n ); dfs( 0, 1, 0 ); printf( "%I64d\n", sum - ans ); } return 0; }