数论训练之三

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
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/wzxbeliever/p/11642262.html