描述
题解
今天做了两个题,都有些懵,这道题一开始想着要dp,可是,屡试不通……
还是老办法,找题解喽,毕竟思而不学则殆,是需要学习一下这种题型的解题思路了。
看到一篇题解,看得不是完全懂,大体的算法思路懂了,可是推导的过程有些懵逼……
题解如下(题解来自ITAK大牛的博客):
这个题目直接想的话没法做,所以就是间接的想,也就是采用容斥原理从反面来想,
也就是说用总数减去不能够满足三角形的方法数,那么先来求总数,
因为现在的问题是将L分成四份, 一份给a一份给b一份给c剩下的就是剩下的了,
那么分成的四份可能有0 不满足挡板法的条件,所以我们就将L+4,
那么现在在分成四份就符合条件啦,所以总的方法数就是 C(L+4−1,4−1),
那么现在再来求不满足三角形条件的方法数,
因为三角形一定满足一个条件是两边之和大于第三边,
所以我们只要求出两条较小的边小于等于最大边就不满足条件了,
然后根据这个可以列一个方程,假设a现在加上了x,b现在加上了y,
c现在加上了z(假设a是最大边),方程如下:
b+y+c+z≤a+x
然后因为所有数的和一定是a+b+c+L,所以最大值不可能超过a+b+c+L,
那么:
b+c≤a+b+c+L−(a+x)
综上所以有:
b+c≤min(a+b+c+L−a,a+x)
然后在利用挡板法求出不能组成三角形的方法数,是C(min−b−c+2,2),
所以就可以写了。
代码
#include <iostream>
using namespace std;
typedef long long ll;
ll Solve(ll a, ll b, ll c, ll L) // a是三边之间最大的
{
ll tmp = a + b + c + L;
ll ans = 0;
for (ll i = 0; i <= L; i++)
{
ll tmp_ = min(tmp - a - i, i + a);
if (b + c <= tmp_)
{
ans += (tmp_ - b - c + 2) * (tmp_ - b - c + 1) / 2;
}
}
return ans;
}
int main()
{
ll a, b, c, L;
while (cin >> a >> b >> c >> L)
{
// 挡板法求所有可能数
ll ans = (L + 3) * (L + 2) * (L + 1) / 6;
ans -= Solve(a, b, c, L);
ans -= Solve(b, a, c, L);
ans -= Solve(c, a, b, L);
cout<< ans <<endl;
}
return 0;
}