UVA 10458 - Cricket Ranking(容斥原理)

UVA 10458 - Cricket Ranking

题目链接

题意:给定k个区间,要求用这些数字范围去组合成n,问有几种组合方式

思路:容斥原理,容斥是这样做:已知n个组成s,不限值个数的话,用隔板法求出情况为C(s + n - 1, n - 1),但是这部分包含了超过了,那么就利用二进制枚举出哪些是超过的,实现把s减去f(i) + 1这样就保证这个位置是超过的,减去这部分后,有多减的在加回来,这就满足了容斥原理的公式,个数为奇数的时候减去,偶数的时候加回

代码:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
typedef long long ll;
const int MAXN = 1005;

struct bign {
    int len;
    ll num[MAXN];

    bign () {
	len = 0;
	memset(num, 0, sizeof(num));
    }
    bign (ll number) {*this = number;}
    bign (const char* number) {*this = number;}

    void DelZero ();
    void Put ();

    void operator = (ll number);
    void operator = (char* number);

    bool operator <  (const bign& b) const;
    bool operator >  (const bign& b) const { return b < *this; }
    bool operator <= (const bign& b) const { return !(b < *this); }
    bool operator >= (const bign& b) const { return !(*this < b); }
    bool operator != (const bign& b) const { return b < *this || *this < b;}
    bool operator == (const bign& b) const { return !(b != *this); }

    void operator ++ ();
    void operator -- ();
    bign operator + (const int& b);
    bign operator + (const bign& b);
    bign operator - (const int& b);
    bign operator - (const bign& b);
    bign operator * (const ll& b);
    bign operator * (const bign& b);
    bign operator / (const ll& b);
    //bign operator / (const bign& b);
    int operator % (const int& b);
};

/*Code*/

int k;
long long n, f[10];

int bitcount(int x) {
    return x == 0 ? 0 : bitcount(x>>1) + (x&1);
}

bign C(long long n, long long m) {
    bign ans = 1;
    for (long long i = 0; i < m; i++)
	ans = ans * (n - i) / (i + 1);
    return ans;
}

int main() {
    while (~scanf("%d%lld", &k, &n)) {
	long long l, r;
	for (int i = 0; i < k; i++) {
	    scanf("%lld%lld", &l, &r);
	    f[i] = r - l;
	    n -= l;
	}
	bign ans1 = 0LL, ans2 = 0LL;
	for (int i = 0; i < (1<<k); i++) {
	    long long s = n;
	    for (int j = 0; j < k; j++) {
		if (i&(1<<j)) {
		    s -= f[j] + 1;
		    if (s < 0) break;
		}
	    }
	    if (s < 0) continue;
	    if (bitcount(i)&1) ans2 = ans2 + C(s + k - 1, k - 1);
	    else ans1 = ans1 + C(s + k - 1, k - 1);
	}
	(ans1 - ans2).Put();
	printf("\n");
    }
    return 0;
}

/*********************************************/

void bign::DelZero () {
    while (len && num[len-1] == 0)
	len--;

    if (len == 0) {
	num[len++] = 0;
    }
}

void bign::Put () {
    for (int i = len-1; i >= 0; i--)
	printf("%lld", num[i]);
}

void bign::operator = (char* number) {
    len = strlen (number);
    for (int i = 0; i < len; i++)
	num[i] = number[len-i-1] - '0';

    DelZero ();
}

void bign::operator = (ll number) {

    len = 0;
    while (number) {
	num[len++] = number%10;
	number /= 10;
    }

    DelZero ();
}

bool bign::operator < (const bign& b) const {
    if (len != b.len)
	return len < b.len;
    for (int i = len-1; i >= 0; i--)
	if (num[i] != b.num[i])
	    return num[i] < b.num[i];
    return false;
}

void bign::operator ++ () {
    int s = 1;

    for (int i = 0; i < len; i++) {
	s = s + num[i];
	num[i] = s % 10;
	s /= 10;
	if (!s) break;
    }

    while (s) {
	num[len++] = s%10;
	s /= 10;
    }
}

void bign::operator -- () {
    if (num[0] == 0 && len == 1) return;

    int s = -1;
    for (int i = 0; i < len; i++) {
	s = s + num[i];
	num[i] = (s + 10) % 10;
	if (s >= 0) break;
    }
    DelZero ();
}

bign bign::operator + (const int& b) {
    bign a = b;
    return *this + a;
}

bign bign::operator + (const bign& b) {
    int bignSum = 0;
    bign ans;

    for (int i = 0; i < len || i < b.len; i++) {
	if (i < len) bignSum += num[i];
	if (i < b.len) bignSum += b.num[i];

	ans.num[ans.len++] = bignSum % 10;
	bignSum /= 10;
    }

    while (bignSum) {
	ans.num[ans.len++] = bignSum % 10;
	bignSum /= 10;
    }

    return ans;
}

bign bign::operator - (const int& b) {
    bign a = b;
    return *this - a;
}

bign bign::operator - (const bign& b) {
    ll bignSub = 0;
    bign ans;
    for (int i = 0; i < len || i < b.len; i++) {
	bignSub += num[i];
	if (i < b.len)
	    bignSub -= b.num[i];
	ans.num[ans.len++] = (bignSub + 10) % 10;
	if (bignSub < 0) bignSub = -1;
	else bignSub = 0;
    }
    ans.DelZero();
    return ans;
}

bign bign::operator * (const ll& b) {
    ll bignSum = 0;
    bign ans;

    ans.len = len;
    for (int i = 0; i < len; i++) {
	bignSum += num[i] * b;
	ans.num[i] = bignSum % 10;
	bignSum /= 10;
    }

    while (bignSum) {
	ans.num[ans.len++] = bignSum % 10;
	bignSum /= 10;
    }

    return ans;
}

bign bign::operator * (const bign& b) {
    bign ans;
    ans.len = 0; 

    for (int i = 0; i < len; i++){
	int bignSum = 0;  

	for (int j = 0; j < b.len; j++){
	    bignSum += num[i] * b.num[j] + ans.num[i+j];
	    ans.num[i+j] = bignSum % 10;
	    bignSum /= 10;
	}
	ans.len = i + b.len;  

	while (bignSum){
	    ans.num[ans.len++] = bignSum % 10;
	    bignSum /= 10;
	}
    }
    return ans;
}

bign bign::operator / (const ll& b) {

    bign ans;

    ll s = 0;
    for (int i = len-1; i >= 0; i--) {
	s = s * 10 + num[i];
	ans.num[i] = s/b;
	s %= b;
    }

    ans.len = len;
    ans.DelZero();
    return ans;
}

int bign::operator % (const int& b) {

    bign ans;

    int s = 0;
    for (int i = len-1; i >= 0; i--) {
	s = s * 10 + num[i];
	ans.num[i] = s/b;
	s %= b;
    }

    return s;
}

UVA 10458 - Cricket Ranking(容斥原理),布布扣,bubuko.com

时间: 2024-08-24 10:28:26

UVA 10458 - Cricket Ranking(容斥原理)的相关文章

uva 10458 - Cricket Ranking(容斥+高精度)

题目连接:uva 10458 - Cricket Ranking 题目大意:给定k和n,表示有k个比赛,总共要的n分,每个比赛可以得l~r的分数,问说可以有多少种得分方式. 解题思路:容斥,可以参考Codeforces 451E. #include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const int MAXN = 1005

uva 12075 - Counting Triangles(容斥原理)

题目链接:uva 12075 - Counting Triangles 题目大意:一个n?m的矩阵,求说有选任意三点,可以组成多少个三角形. 解题思路:任意选三点C(3(n+1)?(m+1))但是有些组合是不可行得,即为三点共线,除了水平和竖直上的组合,就是斜线上的了,dp[i][j]即为ij情况下的斜线三点共线. #include <cstdio> #include <cstring> typedef long long ll; const int N = 1005; ll dp

Uva 10325 The Lottery ( 容斥原理 )

Uva 10325 The Lottery ( 容斥原理 ) #include <cstdio> #include <cstring> typedef long long LL; LL x[20],n, m; LL gcd( LL a, LL b ) { return ( b == 0 ) ? a : gcd( b, a % b ); } LL lcm( LL a, LL b ) { return a / gcd( a, b ) * b; } void solve() { LL a

UVA 10542 - Hyper-drive(容斥原理)

UVA 10542 - Hyper-drive 题目链接 题意:给定一些个d维的方块,给定两点,求穿过多少方块 思路:容斥原理,每次选出一些维度,如果gcd(a, b),就会穿过多少点,对应的就减少穿过多少方块,所以最后得到式子d1 + d2 + .. dn - gcd(d1, d2)..+gcd(d1, d2, d3)... 代码: #include <cstdio> #include <cstring> typedef long long ll; int t, d, a[15]

UVa 11806 拉拉队(容斥原理)

https://vjudge.net/problem/UVA-11806 题意: 在一个m行n列的矩形网格里放k个相同的石子,有多少种方法?每个格子最多放一个石子,所有石子都要用完,并且第一行.最后一行.第一列.最后一列都得有石子. 思路: 如果考虑各种情况的话很复杂,设满足第一行没有石子的方案集为A,最后一行没有石子的方案集为B,第一列没有石子的方案集为C,最后一列没有石子的方案集为D,全集为S. 一个容斥原理的公式就可以解答出来,用二进制来枚举方案集的组合. 1 #include <iost

UVA - 11806 Cheerleaders (容斥原理)

题意:在N*M个方格中放K个点,要求第一行,第一列,最后一行,最后一列必须放,问有多少种方法. 分析: 1.集合A,B,C,D分别代表第一行,第一列,最后一行,最后一列放. 则这四行必须放=随便放C[N * M][K] - 至少有一行没放,即ABCD=随便放-A的补集 ∪ B的补集 ∪ C的补集 ∪ D的补集. 2.A的补集 ∪ B的补集 ∪ C的补集 ∪ D的补集,可用容斥原理计算,二进制枚举即可. #include<cstdio> #include<cstring> #incl

UVA - 1312 Cricket Field 构造

题目大意:在一个W * H的网格中有n棵树,要求你在这个网格中找出最大个的一个正方形,这个正方形内部不能有树,边上可以有树 解题思路:刚开始以为要暴力枚举每一个点,结果发现错了,其实这题就像UVA - 1382 Distant Galaxy这题一样,只不过这个是要找正方形,找正方形和找矩形类似,只需要取矩形的最小边就可以了 #include<cstdio> #include<algorithm> using namespace std; #define maxn 110 struc

UVA 1312 Cricket Field

题意: 在w*h的坐标上给n个点, 然后求一个最大的矩形,使得这个矩形内(不包括边界)没有点,注意边界上是可以有点的. 分析: 把坐标离散化.通过两重循环求矩形的高,然后枚举,看是否能找到对应的矩形. 代码: #include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int

UVa 1312 Cricket Field (枚举+离散化)

题意:在w*h的图上有n个点,要求找出一个正方形面积最大,且没有点落在该正方形内部. 析:枚举所有的y坐标,去查找最大矩形,不断更新. 代码如下: #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <