容斥原理

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

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

POJ 1091 跳蚤

中文题,有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;
}
View Code

 

posted @ 2015-03-18 00:02  L__J  阅读(152)  评论(0编辑  收藏  举报