数论训练之三
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<cstdio>
#include<cstring>
#include<algorithm>
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;
}