数论训练之三

http://codeforces.com/problemset/problem/571/A

冥思苦想怎么加才能保证能组成三角形,并且要求其方案数

然后就无奈看题解

发现其实可以容斥一下总方案数-不合法的方案数=答案

普及一下排列组合

P(n,m)表示n个中选出m个排列

P(n,m)=n(n-1)(n-2)(n-3)....(n-m+1)=n!/(n-m)!

分别表示第一个位置可以选的数有n

第二个可以选的数有n-1个(排除第一个选的)

。。。。。。

特别的

p(n,n)=n!

特别的

当有N1个元素相等,N2个元素相等,N3个元素相等.......Nm个元素相等,且N1+N2+N3+.....+Nm=N

叫可重集的排列

P=N!/(N1!N2!....Nm!)

C(n,m)表示从n个中选出m个不同的组合

C(n,m)=P(n,m)/p(m,m)=n!/(n-m)!m!

特别的

可重复组合为C(n+m-1,m)

插板法为C(n+m-1,m-1)

回到正题

对于本题来说就可以用插板法

只要满足下面3个条件之一即可

a+x+b+y<=c+z

a+x+c+z<=b+y

b+y+c+z<=a+x

而且这三个条件最多只会有一个成立!!!!!!!!

另外还要满足x+y+z<=l

对于第一种,即为x+y<=min(c+z-a-b,l-z)方案数

枚举z即可

其他两种同理

#include
#include
#include
typedef long long ll;
using namespace std;
int a,b,c,l;ll ans;

ll f(int a,int b,int c){
    ll res=0;
    for (int i=0;i<=l;i++){
        int t=min(l-i,c+i-a-b);
        if (t>=0) res+=1ll*(t+2)*(t+1)/2;
    }
    return res;
}

int main(){
    scanf("%d%d%d%d",&a,&b,&c,&l);
    for (int i=0;i<=l;i++) ans+=1ll*(i+2)*(i+1)/2;
    ans-=f(c,b,a),ans-=f(b,a,c),ans-=f(c,a,b);
    printf("%I64d\n",ans);
    return 0;
}

你可能感兴趣的:(数论训练之三)