#317 (div.2) C. Lengthening Sticks

1.题目描述:点击打开链接

2.解题思路:本题利用减法原理解决。比赛时候暴力枚举果断超时==。正确的做法是用总体方案-不合理的方案数。显然,总体方案的个数等价于求解x1+x2+x3+x4=l的非负整数解的个数,利用组合数学的结论等于C(l+4-1,4-1)=C(l+3,3)。其中x4表示没有使用的长度,它从0取到l。接下来就是考虑不合理的方案数目。我们先考虑让a增加一个La,变成a+La,我们令i=a+La,maxsum=a+b+c+l,这时我们考虑b+c的变化范围,显然b+c不能超过i,又由于总长maxsum的限制,b+c不能超过maxsum-i,因此b+c最大只能变化到min(i,maxsum-i),令x=min(i,maxsum-i)-b-c+1,表示总共的变化量大小。即Lb+Lc≤x,这个式子的方案数等价于Lb+Lc+tmp=x的方案数,类似于前面的讨论,等于C(x+3-1,3-1)=C(x+2,2)=(x+2)(x+1)/2。即第一种不合理的方案数是(min(i,maxsum-i)-b-c+1)*(min(i,maxsum-i)-b-c+2)/2。同理可以找到b,c的不合理方案数,最后减去它们就是答案。

3.代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;



ll a,b,c,l;

int main()
{
    while(cin>>a>>b>>c>>l)
    {
        ll ans=0;
        ll maxsum=a+b+c+l;
        for(ll i=a;i<=a+l;i++)
            if(b+c>i)continue; //i表示a刚刚不能构成三角形的长度
        else  
        {
            ans+=(min(i,maxsum-i)-b-c+1)*(min(i,maxsum-i)-b-c+2)/2;//Lb+Lc的可变范围是0~min(i,maxsum-i)-b-c,有min(i,maxsum-i)-b-c+1个值
        }
        for(ll i=b;i<=b+l;i++)//同上
            if(a+c>i)continue;
        else ans+=(min(i,maxsum-i)-a-c+1)*(min(i,maxsum-i)-a-c+2)/2;
        for(ll i=c;i<=c+l;i++)
            if(b+a>i)continue;
        else ans+=(min(i,maxsum-i)-b-a+1)*(min(i,maxsum-i)-b-a+2)/2;
        printf("%I64d\n",(l+1)*(l+2)*(l+3)/6-ans);  //总方案数是C(l+3,3)
    }
}

你可能感兴趣的:(计数,组合数学)