zoukankan      html  css  js  c++  java
  • 容斥原理

    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
    ", 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
    ", 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
    ", 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
    ", 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
    ", sum - ans );
        }
        return 0;
    }
    View Code
  • 相关阅读:
    sqlserver2005系统表、视图研究2
    SQLServer2005新分页方法
    应该多了解一些工具
    关于SQLServer的小技巧
    EasyUI DataGrid使用Json加载不了数据
    js跨域及解决方案
    关于Master Page的css和js文件引用问题
    嵌套母版页
    SSMS获取存储过程中的返回值和output值
    静态构造函数
  • 原文地址:https://www.cnblogs.com/LJ-blog/p/4346058.html
Copyright © 2011-2022 走看看