题目描述:
You are given three sticks with positive integer lengths of a, b, and c centimeters. You can increase length of some of them by some positive integer number of centimeters (different sticks can be increased by a different length), but in total by at most l centimeters. In particular, it is allowed not to increase the length of any stick.
Determine the number of ways to increase the lengths of some sticks so that you can form from them a non-degenerate (that is, having a positive area) triangle. Two ways are considered different, if the length of some stick is increased by different number of centimeters in them.
Input
The single line contains 4 integers a, b, c, l (1 ≤ a, b, c ≤ 3·105, 0 ≤ l ≤ 3·105).
Output
Print a single integer — the number of ways to increase the sizes of the sticks by the total of at most l centimeters, so that you can make a non-degenerate triangle from it.
题解:
很好地一道题目。给出以下解法。
(1)最笨最麻烦的解法:我们认定a是最的边,其他的<=a.那么我们暴力枚举a+x的x,设b+i,那么i的定义域我们知道了.对于一个i,c的可取范围其实是一个一次函数,但是这个一次函数是分段的.所以我们要耐心的解出一个有定义域且分段的一次函数.很麻烦,可以用很多if,也可以合起来写.之后是容斥的部分,很简单,暴力就好.
(2)思考一点反面:当我们认定a是最大的边的时候,b和c算反面。那么都有什么反面?b大于a,c大于a,b和c都小于等于a,但是b+c<=a. 前一部分用容斥,后一部分是重点:在三角形中很常用的技巧.b+c<=a,那么自然而然的b<=a,c<=a.这样就做了.
(3)整体思考反面.很好的思维:首先笨笨的算出所有的情况.之后减去不合法的:不合法的中,我们认定a是这种情况下最大的.那么,此时b和c已经天然有了<=a的性质,只需要减去b+c<=a的情况.之后我们容斥,a和b同样都是最大的,c比较小,这种情况没有不合法情况,abc都最大也没有不合法情况.所以就结束了.
重点:
(1)三角形判定,认定一条边是最大值.之后的只需要b+c>a就好了.
(2)解法一中的用函数表示对函数求和的方法.
(3)逆向思维.特别是三角形判定有一个最大边什么的.
(4)容斥的掌握,减去的东西应该是上一步大前提下多算的.
代码:
//三种解法都写在下面了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ll i = a;i < b;i++)
#define REP_D(i, a, b) for(ll i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const double EPS = 1e-9;
ll a, b, c, s;
ll gao(ll a, ll b, ll xl, ll xr)
{
if(xl > xr)
return 0;
if(a*xl + b < 0 && a*xr+b<0)
return 0;
double key = -b*1.0/a;
ll keyx;
if(a > 0)
{
keyx = (key - EPS);
keyx++;
}
else
{
keyx = (key + EPS);
}
if(a*xl + b < 0)
{
xl = keyx;
}
if(a*xr + b < 0)
{
xr = keyx;
}
ll ans = b*(xr-xl+1);
ll tmp = (xr+xl)*(xr-xl+1)/2;
ans += tmp*a;
return ans;
}
ll first_old(ll a, ll b, ll c)
{
ll ans = 0;
ll i1, i2;
ll jl, jr;
ll tmp, oldAns;
for(ll x = 0; x<=s; x++)
{
tmp = 0;
oldAns = ans;
ll keyi = min(a+x-b, s - x);
if(keyi < 0)
continue;
i1 = a+x+1-b-c;
i2 = s-2*x-a+c;
i1 = min(keyi, i1);
i2 = min(keyi, i2);
if(i1 < 0 && i2 < 0)
{
jl = 0;
jr = keyi;
ans += gao(-1, s-x+1, jl, jr);
}
else if(i1 < 0)
{
jl = 0;
jr = i2;
ans += gao(0, a+x-c+1, jl, jr);
jl = i2+1;
jr = keyi;
ans += gao(-1, s-x+1, jl, jr);
}
else if(i2 < 0)
{
jl = 0;
jr = i1;
ans += gao(0, s - 2*x - a - 1 + b +c+1, jl, jr);
jl = i1+1;
jr = keyi;
ans += gao(-1, s-x+1, jl, jr);
}
else
{
if(i1==i2)
{
jl = 0;
jr = i1;
ans += gao(1, b-1+1, jl, jr);
jl = i1+1;
jr = keyi;
ans += gao(-1, s-x+1, jl, jr);
}
else if(i1 < i2)
{
jl = 0;
jr = i1;
ans += gao(1, b-1+1, jl, jr);
jl = i1+1;
jr = i2;
ans += gao(0, a+x-c+1, jl, jr);
jl = i2+1;
jr = keyi;
ans += gao(-1, s-x+1, jl, jr);
}
else
{
jl = 0;
jr = i2;
ans += gao(1, b-1+1, jl, jr);
jl = i2+1;
jr = i1;
ans += gao(0, s - 2*x - a - 1 + b +c+1, jl, jr);
jl = i1+1;
jr = keyi;
ans += gao(-1, s-x+1, jl, jr);
}
}
// for(ll bx = 0;bx+x<=s;bx++)
// {
// for(ll cx = 0;cx+bx+x<=s;cx++)
// {
// if(a+x >= b+bx && a+x >= c+cx)
// {
// if(a+x+b+bx>c+cx && a+x+c+cx>b+bx && b+bx+c+cx>a+x)
// {
// tmp++;
// }
// }
// }
// }
//printf("x is %I64d ans is %I64d tmp is %I64d\n", x, ans - oldAns, tmp);
}
return ans;
}
ll first(ll a, ll b, ll c)
{
ll ans = 0;
for(ll x = 0; x<=s; x++)
{
if(b > a+x || c > a+x)
continue;
ll tmp = (s - x + 2)*(s-x + 1)/2;
if(s-x-(a+x+1-b) >= 0)
tmp -= (s-x-(a+x+1-b)+2)*(s-x-(a+x+1-b)+1)/2;
if(s-x-(a+x+1-c) >= 0)
tmp -= (s-x-(a+x+1-c)+2)*(s-x-(a+x+1-c)+1)/2;
if(s - x - (a+x+1-b) - (a+x+1-c)>=0)
{
tmp += (s - x - (a+x+1-b) - (a+x+1-c)+2)*(s - x - (a+x+1-b) - (a+x+1-c)+1)/2;
}
ll sum = a+x - b - c;
if(sum >= 0)
{
sum = min(sum, s - x);
tmp -= (sum+2)*(sum+1)/2;
}
ans += tmp;
// ll tmp2 = 0;
// for(ll bx = 0; bx+x<=s; bx++)
// {
// for(ll cx = 0; cx+bx+x<=s; cx++)
// {
// if(a+x >= b+bx && a+x >= c+cx)
// {
// if(a+x+b+bx>c+cx && a+x+c+cx>b+bx && b+bx+c+cx>a+x)
// {
// tmp2++;
// }
// }
// }
// }
// printf("x is %I64d ans is %I64d tmp is %I64d\n", x, tmp, tmp2);
}
return ans;
}
ll second(ll a, ll b, ll c)
{
ll ans = 0;
for(ll i = max(a, b);; i++)
{
if(i < c)
continue;
ll t = i - a + i - b;
t = s - t;
if(t < 0)
break;
if(c + t > i)
{
ans += i-c+1;
}
else
{
ans += t+1;
}
}
return ans;
}
ll third(ll a, ll b, ll c)
{
ll ans = 0;
ll t = max(a, b);
t = max(t, c);
for(ll i = t;; i++)
{
ll used = 3*i - a - b - c;
if(used > s)
break;
ans++;
}
return ans;
}
void solve_old()
{
ll ans = 0;
ans += first(a, b, c);
ans += first(b, a, c);
ans += first(c, a, b);
ans -= second(a, b, c);
ans -= second(b, c, a);
ans -= second(a, c, b);
ans += third(a, b, c);
printf("%I64d\n", ans);
}
ll new_first(ll a, ll b, ll c)
{
ll ans = 0;
for(ll x = 0;x<=s;x++)
{
if(a+x-b-c<0)
continue;
ll tmp = min(a+x-b-c, s-x);
ans += (tmp+2)*(tmp+1)/2;
}
return ans;
}
ll new_second(ll a, ll b, ll c)
{
ll ans = 0;
for(ll x = max(a, b);;x++)
{
if(x-a+x-b > s)
break;
ll tmp = s - (x-a+x-b);
if(2*x-c>0)
tmp -= (2*x-c);
if(tmp >= 0)
ans += tmp+1;
}
return ans;
}
void solve()
{
ll ans = (s+3)*(s+2)*(s+1)/6;
ans -= new_first(a, b, c);
ans -= new_first(b, a, c);
ans -= new_first(c, a, b);
//ans += new_second(a, b, c);
//ans += new_second(b, c, a);
//ans += new_second(a, c, b);
printf("%I64d\n", ans);
}
int main()
{
freopen("1Ain.txt", "r", stdin);
//freopen("1Aout.txt", "w", stdout);
while(scanf("%I64d%I64d%I64d%I64d", &a, &b, &c, &s) != EOF)
{
solve();
}
return 0;
}