UVA 10458 Cricket Ranking (容斥)

Problem F

Cricket Ranking

Input: standard input

Output: standard output

Time Limit: 2 seconds

 

World Cup Cricket 2003 is now going on in South Africa. The final will be held on 23rd March in Johannesburg during the grand occasion in Beverly Hills, California.

Fig : New Wanderers Stadium, Johannesburg.

Many of you may not be interested in cricket, but its really a passion in Indian subcontinent. Ranking of cricketers is a common pheonomenon there. Cricketers are ranked by their performance in both form of cricket ( Test and Oneday). People really enjoy this ranking. They like to see their favourite players as top ranked. They will not be happy if they see Matthew Hayden as top ranked in stead of Sachin Tendulkar or Rahul Dravid. Currently many such rankings are available. And as you have probably guessed, each ranking makes a different player as top ranked.

World Cup committee has decided that they will make a new ranking on the performance of players in the world cup. They want the ranking to be acceptable to the public. The rules are as follows :

  • There are K different departments. Cricketers will be given points in each department depending on their performance.

  • The maximum points for each department are not euqal. Such as Saeed Anwar can get maximum 25 points in batting but Jonty Rhodes can get maximum 10 points for his spectacular fielding.

  • The sum of maximum points of all departments will be exactly N points. And the final ranking will depend on the total earned points out of N points.

    The ranking committee wants popular cricketers get top ranked. To do so they even allow maximum points for fielding more than that of batting. But that can bring lots of criticism. So they decide to fix a range of points for each department. Such as maximum points for batting will be atleast 10 and atmost 15 or for fielding, it will be atleast 8 and atmost 12. But the total points will be 20. Then 3 ranking system is possible, such as :

    BattingFielding
    1010
    119
    128

    In this problem, you have to find out the number of ranking systems possible for given number of departments, range of points for each department and total points.

     

    Input

    Each dataset starts with two positive integer K(1<=K<=7) and N(1<=N<=2000000000). In next few lines there will be 2K positive integers which will successively denote the lower and upper limit of allowable maximum points for each department. Input is terminated by EOF. There may be as many as 500 datsets.


    Output

    For each input print the total number of ranking systems possible maintaining the given constraints. The final answer can be as large as 60-digits.

     

    Sample Input

    4 101 1 2 2 3 3 4 44 101 1 2 2 3 3 3 32 101 10 1 102 2010 158 12

    Sample Output

    1093

Author : Md. Kamruzzaman

The Real Programmers' Contest-2


思路:首先题目等价与有K个未知数,知道了每个数的上界和下界,也知道未知数的和为N,问有多少种解。首先我们将N减去每个数的下界,然后就等价与知道每个数的上界,求解数,由于只有K个数,我们能直接用容斥来做,用没有限制的方案数减去不符合条件的方案数就行了。不符合的怎么求? 其中一个数必须超过上界方案数 - 其中两个必须上界方案数 + 其中三个.......   超过上界的那些数就先取上界+1, 然后就变成所有数都没有限制,和为N'的解数了。具体看代码


代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include <thread>
#include <cstring>
#include <map>
#include <stdio.h>
#include <cmath>
#include <cassert>
#include <math.h>
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,b,a) for(int i = (b); i >= (a); --i)
#define clr(a,x) memset(a,(x),sizeof(a))
#define LL long long
#define eps 1e-10
using namespace std;

void read_int(int & x)
{
    char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    x = ch - '0'; ch = getchar();
    while ('0' <= ch && ch <= '9') {
        x = 10 * x + ch - '0';
        ch = getchar();
    }
}

const int maxl = 18;
const int bitlen = 4;
char buffer[maxl * bitlen + 10];
const int MAXL = 10000;

LL tmp[bitlen * maxl];
LL q[bitlen * maxl];

struct Bignum
{
    int a[maxl];
    int sz;
    bool read()
    {
        memset(a, 0, sizeof(a));
        sz = 0;
        if (scanf("%s", buffer) != 1) return false;
        int n = strlen(buffer);
        int i;
        for (i = n - 1; i >= 0; i -= bitlen)
        {
            LL x = 0, y = 1;
            for (int j = i; j > i - bitlen && j >= 0; --j)
            {
                x += y*(buffer[j] - '0');
                y *= 10;
            }
            a[sz++] = x;
        }
        return true;
    }

    Bignum()
    {
        memset(a, 0, sizeof(a));
        sz = 0;
    }

    Bignum(LL x)
    {
        memset(a, 0, sizeof(a));
        sz = 0;
        if (x == 0) sz = 1;
        while (x != 0)
        {
            a[sz++] = x % MAXL;
            x /= MAXL;
        }
    }
    Bignum(const Bignum&bg)
    {
        sz = bg.sz;
        memset(a, 0, sizeof(a));
        for (int i = 0; i < sz; ++i) a[i] = bg.a[i];
    }

    int cmp(const Bignum&bg) const
    {
        if (sz>bg.sz) return 1;
        else if (sz < bg.sz) return -1;
        for (int i = sz-1; i >= 0; --i)
        if (a[i] < bg.a[i])  return -1;
        else if (a[i]>bg.a[i]) return 1;
        return 0;
    }

    bool operator<(const Bignum&bg) const    { return cmp(bg) < 0; }
    bool operator==(const Bignum&bg) const { return cmp(bg) == 0; }
    bool operator<=(const Bignum&bg) const { return cmp(bg) <= 0; }
    bool operator>(const Bignum&bg) const { return cmp(bg)>0; }
    bool operator>=(const Bignum&bg) const { return cmp(bg) >= 0; }
    bool operator!=(const Bignum&bg) const { return cmp(bg) != 0; }

    Bignum operator=(const Bignum&bg)
    {
        sz = bg.sz;
        memset(a, 0, sizeof(a));
        for (int i = 0; i < sz; ++i) a[i] = bg.a[i];
        return *this;
    }
    void add(const Bignum&bg)
    {
        sz = max(sz, bg.sz);
        for (int i = 0; i < sz; ++i)
        {
            a[i] += bg.a[i];
            a[i + 1] += a[i] / MAXL;
            a[i] %= MAXL;
        }
        while (a[sz] != 0) ++sz;
    }
    Bignum operator+(const Bignum&bg)
    {
        if (bg == 0) return *this;
        Bignum ret = *this;
        ret.add(bg);
        return ret;
    }


    void sub(const Bignum&small)
    {
        for (int i = 0; i < sz; ++i)
        {
            a[i] -= small.a[i];
            if (a[i] < 0)
            {
                int j = i + 1;
                a[i] += MAXL;
                while (--a[j]<0)
                {
                    a[j] += MAXL;
                    ++j;
                }
            }
        }
        while (sz>1 && a[sz - 1] == 0) --sz;
    }
    void mul(const Bignum&b)
    {
        memset(tmp,0,sizeof(tmp));
        for(int i=0;i<sz;++i) {
            for(int j=0;j<b.sz;++j) {
                tmp[i+j]+=a[i]*b.a[j];
                tmp[i+j+1]+=tmp[i+j]/MAXL;
                tmp[i+j]%=MAXL;
            }
        }
        sz+=b.sz;
        while(tmp[sz]>0) {
            tmp[sz+1]+=tmp[sz]/MAXL;
            tmp[sz]%=MAXL;
            ++sz;
        }
        while(sz>1&&tmp[sz-1]==0) --sz;
        for(int i=0;i<sz;++i) a[i]=tmp[i];
    }

    Bignum operator-(const Bignum&small)
    {
        if (small == 0) return *this;
        int cp = cmp(small);
        if (cp == 0) return 0;
        Bignum A = *this, B = small;
        A.sub(B);
        return A;
    }

    Bignum operator/(LL x)
    {
        Bignum ret = *this;
        LL y = 0;
        for (int i = sz - 1; i >= 0; --i)
        {
            y = y*MAXL + ret.a[i];
            ret.a[i] = y / x, y %= x;
        }
        while (ret.sz > 1 && ret.a[ret.sz - 1] == 0) --ret.sz;
        return ret;
    }

    LL operator%(LL x)
    {
        LL y = 0;
        for (int i = sz - 1; i >= 0; --i)
        {
            y = y*MAXL + a[i];
            if (y >= x)  y %= x;
        }
        return y;
    }

    Bignum operator*(const Bignum&bg)
    {
        Bignum ret=*this;
        ret.mul(bg);
        return ret;
    }


    Bignum pow(LL x)
    {
        Bignum ret = 1, base = *this;
        while (x)
        {
            if (x & 1) ret = ret*base;
            base = base*base;
            x >>= 1;
        }
        return ret;
    }
    Bignum operator*(LL x)
    {
        return *this*Bignum(x);
    }

    bool Try_sub(char *s,char *t,int lent,int lens)
    {
        if(lent>lens) return false;
        for(int i=0;i<lens;++i) q[i]=s[i];

        bool ok=true;
        for(int i=0;i<lens;++i) {
            s[i]-=t[i];
            if(s[i]>=0) continue;
            int j=i+1;
            s[i] += 10;
            while (j<lens && --s[j]<0)
            {
                s[j] += 10;
                ++j;
            }
            if(j>=lens) { ok=false; break; }

        }
        if(ok) return true;
        for(int i=0;i<lens;++i) s[i]=q[i];
        return false;
    }
    Bignum operator/(const Bignum&bg)
    {
        int cp=cmp(bg);
        if(cp==0) return 1;
        else if(cp<0) return 0;
        char * s= new char[bitlen*sz+5], *t=new char [bitlen*sz+5];
        char * ans= new char [bitlen*sz+5];
        int lens=0,lent=0;
        s[lens]=t[lent]=0;
        for(int i=0;i<sz;++i) {
            int x=a[i];
            for(int j=0;j<4;++j) {
                s[lens++]=x%10;
                s[lens]=0;
                x/=10;
            }
            x=bg.a[i];
            for(int j=0;j<4;++j) {
                t[lent++]=x%10;
                t[lent]=0;
                x/=10;
            }
        }
        while(lent>1 && t[lent-1]==0) --lent;
        while(lens>1 && s[lens-1]==0) --lens;
        for(int i=lent;i<lens;++i) t[i]=0;
        for(int i=lens-1;i>=0;--i) {
            ans[i]=0;
            while(Try_sub(s+i,t,lent,lens-i)) ++ans[i];
        }
        for(int i=lens;i<=lens+4;++i) ans[i]=0;
        Bignum ret;
        for(int i=0;i<lens;i+=4) {
            ret.a[i/4]=1000*ans[i+3]+100*ans[i+2]+10*ans[i+1]+ans[i];
        }
        ret.sz=sz;
        while(ret.sz>1 && ret.a[ret.sz-1]==0) --ret.sz;
        delete [] s; delete [] t; delete [] ans;
        return ret;
    }
    Bignum operator%(const Bignum&bg)
    {
        if (bg == 0) return 0;
        Bignum ret = *this;
        ret = (ret / bg)*bg;
        return *this - ret;
    }

    void output() const
    {
        printf("%d", a[sz - 1]);
        for (int i = sz - 2; i >= 0; --i) printf("%04d", a[i]);
        printf("\n");
    }
};

LL d[10];
Bignum C(LL n,LL m)
{
    if (n < m) return 0;
    else if (n == m) return 1;
    else if (m == 0) return 1;
    Bignum ret = 1;
    rep(i,0,m) {
        ret = ret * n;
        --n;
    }
    ret = ret / d[m];
    return ret;
}

int K,N;
int low[11],high[11];
int limit[11];
int mask;

Bignum Cal(LL n)
{
    if (n == 0) return 1;
    else if (n < 0) return 0;
    Bignum ans = 0;
    Bignum t;
    rep(i,1,K+1) {
        t = C(K,i) * C(n-1,i-1);
        ans.add(t);
    }
    return ans;
}

Bignum Cal()
{
    int flag;
    Bignum A = 0, B = 0;
    rep(s,0,mask) {
        flag = 0;
        LL S = N;
        rep(j,0,K) if (s & (1<<j)) {
            flag ^= 1;
            S -= limit[j] + 1;
        }
        if (!flag) A.add(Cal(S));
        else B.add(Cal(S));
    }
    return A - B;
}

void solve()
{
    rep(i,0,K) {
        read_int(low[i]);
        read_int(high[i]);
        N -= low[i];
        high[i] -= low[i];
        limit[i] = high[i];
    }
    //    scanf("%d%d",low+i,high+i);
    Bignum A = 0;
    mask = (1<<K);
    A = Cal();
    A.output();
}

void Getinput()
{
    freopen("in.txt","w",stdout);
    int T = 500; N = 2000000000;
    while (T--) {
        K = 7; printf("%d %d\n",K,N);
        rep(i,0,K) {
            printf("%d %d\n",rand()+1,2000000000-rand());
        }
        puts("");
    }
}

int main()
{
   // Getinput();return 0;
    #ifdef ACM
        freopen("in.txt", "r", stdin);
       // freopen("out.txt","w",stdout);
    #endif // ACM
    d[0] = 1;
    rep(i,1,10) d[i] = d[i-1] * i;
    while (scanf("%d%d",&K,&N)==2) {
        solve();
    }
}




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值