Codeforces Round #317 A. Lengthening Sticks(组合+容斥)

最后更新于:2022-04-01 15:52:42

之前也遇到过好几次这种类型的题目了, 但是这次还是没有在比赛中做出来。 因为输入只有4个数, 可变化的状态很少, 但是数据范围又很大, 所以不可能是DP之类的, 一定是一道数学题。   这种特点的题目我们很容易想到排列组合, 然而排列组合往往又会带来重复计数的问题, 所以往往这类题目又需要夹杂容斥定理, 可以说是约定俗称的题目类型。 那么不难想到, 用总的组合情况减去不成立的情况(不成立的情况往往好求)。   对于总的情况, 我们不妨从0枚举到l,枚举三根木棒增加长度的总和i。 那么我们可以将其想象成一根长i的木棒,要将其分成3份。  就行在木棒上切两刀。 但是由于增加的长度可以为0, 所以两刀可以切在一点。   例如: i = 5   那么如果两刀都切在3上, 三根木棒分别增加3、0、2;  所以假设第一刀切在0点, 那么第二刀有l+1种可能:0、1、2.....l 。假设第一刀在1,那么第二刀有l种可能, 以此类推。。。 所以总的方案数为(l+1)+l+(l-1)+(l-2)+......+1。一共(l+2)*(l+1)/2种可能。 接下来排除不可能的情况。  我们不妨假设a+i最长(i=0,1,2....l)。 那么该边最长,我们可以算出来该边和其他两边和的差值,那么这一段长度是可以像一开始一样求组合数的,因为无论怎么组合,a+i仍然是最长的。 细节参见代码: ~~~ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> typedef long long ll; using namespace std; ll a,b,c,l; ll solve(ll a, ll b, ll c) { ll cur = 0; for(ll i=max(b+c-a,0ll);i<=l;i++) { ll res = l - i; ll v = min(res, a+i-b-c); cur += (v+2)*(v+1)/2; } return cur; } int main() { scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&l); ll ans = 0; for(ll i=0;i<=l;i++) { ans += (i+2)*(i+1)/2; } ans -= solve(a,b,c); ans -= solve(b,a,c); ans -= solve(c,a,b); printf("%I64d\n",ans); return 0; } ~~~
';