容斥原理水题选做

今天wxhRound考了一道不能再简单的容斥,完全做不来,感觉容斥很弱


[UVA10325] The Lottery


题意:求1~n中不能被给定m个数中任意一个数整除的数的个数


答案就是n-(被m个数中任意一个数整除的数的个数)
后面这个算法就是:
被1个数整除的数的个数- 被2个数整除的数的个数+被3个数整除的数的个数。。。。。。。

容斥实现方法:二进制压位暴力

我怀疑此题数据不合法,a[i]用%lld读入才AC

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
ll n, m, a[20], ans;
ll gcd( ll a, ll b ){ return b == 0 ? a : gcd( b, a%b ); }
int main(){
	while( scanf( "%d%d", &n, &m ) != EOF ){
		for( int i = 1; i <= m; i++ ) scanf( "%lld", &a[i] );
		ans = n;
		for( int i = 1; i < (1<<m); i++ ){
			ll ret = 1, cnt = 0;
			for( int j = 1; j <= m; j++ )
				if( i & (1<<(j - 1)) ){
					cnt++;
					ret = ret * a[j] / gcd( ret, a[j] );
					if( ret > n ) break;
				}
			if( ret > n ) continue;
			ret = n / ret;
			if( cnt & 1 ) ans -= ret; else ans += ret;
		}
		printf( "%lld\n", ans );
	}
	return 0;
}
[UVA11806] 

Cheerleaders

 

题意:n*m的矩阵,放k个东西。

要求第1,n行 第1,n列必须有的方案数

答案就是所有的-少一行或一列+少两行或一列。。。


容斥实现方法:二进制压位暴力


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <queue>
#include <set>
#include <map>
using namespace std;
int T, n, m, C[405][405], K;
const int mod = 1000007;
int main(){
	for( int i = 0; i <= 400; i++ ){
		C[i][i] = C[i][0] = 1;
		for( int j = 1; j < i; j++ )
			C[i][j] = ( C[i - 1][j] + C[i - 1][j - 1] ) % mod;
	}
	scanf( "%d", &T );
	for( int cas = 1; cas <= T; cas++ ){
		scanf( "%d%d%d", &n, &m, &K );
		int ans = 0;
		for( int i = 0; i < 16; i++ ){
			int r = n, c = m, cnt = 0;
			if( i & 1 ){ r--; cnt++; }
			if( i & 2 ){ r--; cnt++; }
			if( i & 4 ){ c--; cnt++; }
			if( i & 8 ){ c--; cnt++; }
			if( cnt & 1 ) ans = ( ans - C[r*c][K] + mod ) % mod;
			else ans = ( ans + C[r*c][K] ) % mod;
		}
		printf( "Case %d: %d\n", cas, ans );
	}
	return 0;
}

[poj3904]给出n个数,从其中选出4个数,使它们的最大公约数为1,问总共有多少中取法。


答案明显就是:所有排列-1个素数倍数的数+3个素数倍数的数-2个素数倍数的数。。。。

直接考虑容斥绝对过不了

对于每一个数进行质因数分解,最多有6个质因子,可以容斥,把这个数的因数容斥出来

然后答案统计一下就好了


容斥实现方法:二进制压位暴力

ps:此题用莫比乌斯函数也行,但是没必要

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
int tot, pri[10], n, a[10005], one[10005], cnt[10005]; ll fac[10005], ans;
void init(){
	ans = 0;
	memset( cnt, 0, sizeof(cnt) );
	memset( one, 0, sizeof(one) );
}
void solve( int x ){
	memset( pri, 0, sizeof(pri) ); tot = 0;
	for( int i = 2; i * i <= x; i++ )
		if( x % i == 0 ){
			pri[++tot] = i;
			while( x % i == 0 ) x /= i;
		}
	if( x != 1 ) pri[++tot] = x;
	for( int i = 1; i < (1<<tot); i++ ){
		int k = 1, num = 0;
		for( int j = 0; j < tot; j++ )
			if( (1<<j) & i ){
				k *= pri[j + 1];
				num++;
			}
		cnt[k]++;
		one[k] = num;
	}
}
int main(){
	for( int i = 4; i <= 10000; i++ ) fac[i] = 1LL * (i - 3) * (i - 2) * (i - 1) * i / 24;
	while( ~scanf( "%d", &n ) ){
		init();
		for( int i = 1; i <= n; i++ ) scanf( "%d", &a[i] ), solve( a[i] );
		for( int i = 1; i <= 2500; i++ )
			if( cnt[i] ){
				if( one[i] & 1 ) ans -= fac[cnt[i]];
				else ans += fac[cnt[i]];
			}
		printf( "%lld\n", ans + fac[n] );
	}
	return 0;
}

spoj 4168. Square-free integers
求出1~n中不能被“完全平方数”(不含1)整除的数的个数。


我乱想的,搜题解结果(以上)是对的

容斥方法:莫比乌斯函数

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int N = 10000000 + 5;
typedef long long ll;
ll ans, n;
int mul[N], tot, pri[1000005], T; bool isnot[N];
void mobius(){
	for( int i = 2; i <= 10000000; i++ ){
		if( !isnot[i] ) pri[++tot] = i, mul[i] = -1;
		for( int j = 1; j <= tot && i * pri[j] <= 10000000; j++ ){
			isnot[i * pri[j]] = 1;
			if( i % pri[j] == 0 ) mul[i * pri[j]] = 0;
			else mul[i * pri[j]] = mul[i] * -1;
		}
	}
}
int main(){
	mobius();
	scanf( "%d", &T );
	while( T-- ){
		scanf( "%lld", &n );
		ans = n;
		for( ll i = 2; i * i <= n; i++ )
			ans += mul[i] * n / i / i;
		printf( "%lld\n", ans );
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值