码迷,mamicode.com
首页 > 其他好文 > 详细

容斥原理

时间:2015-03-18 01:12:19      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:

HDU 2204 Eddy‘s爱好

直接复制别人的题解,代码自己写的,被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 }
View Code

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 }
View Code

HDU 2841 Visible Trees

还是直接拉题解吧。。感觉别人说的比较清晰,这里

技术分享
 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 }
View Code

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 }
View Code

ZOJ 2836 Number Puzzle

类似的题型。。

技术分享
 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 }
View Code

ZOJ 3233 Lucky Number 

看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 }
View Code

URAL 1091  Tmutarakan Exams

给你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 }
View Code

 

容斥原理

标签:

原文地址:http://www.cnblogs.com/LJ-blog/p/4346058.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!