題意:
給出三個木棒的長度爲、、,再給出一個長度 用來增加三根木棒的長度。三根木棒長度增加之和不能超過,可以爲。問有多少種增長方案使得這三根木棒可以拼成一個三角形。
思路:
最簡單的思路就是令、、分別爲、、三根木棒的長度增加值。則 ,然後令 ,枚舉 ,計算答案。
比賽時我的思路是正向求解這個問題,然後就可以列出下述的式子。
於是問題就變成了一個線性規劃問題
,要求在線性規劃區域中找到有多少個整點。然後就是不斷的公式化簡和推導,然後成功自閉…
其實推導到這個程度之後就應該及時調整解題方向,線性規劃問題的難度是很大的,現在也沒有比較好的通用方向進行解決。所以推導到線性規劃之後就應該及時調轉車頭。
於是我們從反向入手,考慮一下容斥的思想。
枚舉之後,計算有多少種方案使得木棒無法構成三角形。木棒無法構成三角形主要是因爲 最長的木棒長度 剩下兩個木棒長度相加。因此我們枚舉哪一根木棒是最長的木棒。
假如枚舉了木棒 爲最長的木棒,則
可以得到 ,可以求出 ,於是只要給分配的長度大於,就一定不可以構成三角形,於是問題轉化爲 有多少種分配方案。
而所有的分配方案數爲 的方案數。於是問題轉化成了 有多少種不同的分配方案。
首先考慮 有多少種不同的分配方案數。很明顯有 種分配方案,因此枚舉 ,可以發現 的分配方案數爲 。當然也可以直接用組合數來求取答案,用隔板法可以得到總方案數爲 ,至此本題即可解決。
反思:
首先總結一下常見的幾個數學思維。
① 正難則反 —— 容斥思想、反演思想
② 變量思想 —— 設出未知量再不斷進行方程化簡,尋找規律
再總結一下此類數學思維題的一些經驗。
① 一道題拿到手上之後,一定要對問題不斷進行抽象化簡,不斷地深入思考,抽絲剝繭,逐層深入,纔有可能能夠解決這個問題。
② 要擅長去找到規律,從小例子上找到思路然後放到大例子上進行解決。
一個數學式子記錄。
爲常數,一共有 種 <> 分配方案。
代碼:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 1e5+100;
const int M = 1e5+100;
const db EPS = 1e-9;
using namespace std;
int a,b,c,l;
ll ans;
ll calc(ll a1,ll len){
ll tp = ((a1+a1+len-1ll)*len)/2ll;
return tp;
}
ll solve(int a1,int b1,int c1,int len){
ll tp = ceil((b1+c1+len-a1)/2.0-0.1);
tp = max(0ll,tp);
len -= tp;
// LOG1("len",len);
if(len < 0) return 0;
ll hp = calc(1,len+1);
return max(0ll,hp);
}
int main()
{
scanf("%d%d%d%d",&a,&b,&c,&l);
rep(i,0,l){
ll tp1 = max(0ll,calc(1,i+1));
// LOG2("i",i,"tp1",tp1);
ll tp2 = 0;
tp2 += solve(a,b,c,i);
// LOG1("tp2",tp2);
tp2 += solve(b,a,c,i);
// LOG1("tp2",tp2);
tp2 += solve(c,a,b,i);
// LOG1("tp2",tp2);
ans += tp1-tp2;
}
printf("%lld\n",ans);
return 0;
}