【Codeforces Round #317 Div1 —— A】Lengthening Sticks【數學思維題】

題意:

給出三個木棒的長度爲aabbcc,再給出一個長度 ll 用來增加三根木棒的長度。三根木棒長度增加之和不能超過ll,可以爲00。問有多少種增長方案使得這三根木棒可以拼成一個三角形。(1a,b,c3105,0l3105)(1\leq a,b,c\leq 3*10^5,0\leq l\leq 3*10^5)


思路:

最簡單的思路就是令xxyyzz分別爲aabbcc三根木棒的長度增加值。則 x+y+zlx+y+z \leq l,然後令 x+y+z=(0Hl)x+y+z = \text{H} \ (0\leq H\leq l),枚舉 H\text{H},計算答案。

比賽時我的思路是正向求解這個問題,然後就可以列出下述的式子。
{x+y+z=Ha+x<b+y+z+cb+y<a+x+z+cz+c<a+x+b+y \left\{ \begin{aligned} & x+y+z = \text{H} \\ & a+x < b+y+z+c \\ & b+y < a+x+z+c \\ & z+c < a+x+b+y \\ \end{aligned} \right.
於是問題就變成了一個線性規劃問題,要求在線性規劃區域中找到有多少個整點。然後就是不斷的公式化簡和推導,然後成功自閉…

其實推導到這個程度之後就應該及時調整解題方向,線性規劃問題的難度是很大的,現在也沒有比較好的通用方向進行解決。所以推導到線性規劃之後就應該及時調轉車頭。

於是我們從反向入手,考慮一下容斥的思想。枚舉H\text{H}之後,計算有多少種方案使得木棒無法構成三角形。木棒無法構成三角形主要是因爲 最長的木棒長度 >> 剩下兩個木棒長度相加。因此我們枚舉哪一根木棒是最長的木棒。

假如枚舉了木棒 aa 爲最長的木棒,則
{x+y+z=Ha+x>b+y+c+z \left\{ \begin{aligned} & x+y+z = \text{H} \\ & a+x > b+y+c+z \\ \end{aligned} \right.
可以得到 2x>b+c+Ha2*x >b+c+\text{H}-a,可以求出 xbasex\geq base,於是只要給aa分配的長度大於basebase,就一定不可以構成三角形,於是問題轉化爲 x+y+z=Hbasex+y+z = \text{H}-base 有多少種分配方案。

而所有的分配方案數爲 x+y+z=Hx+y+z = \text{H} 的方案數。於是問題轉化成了a+b+c=za+b+c = z 有多少種不同的分配方案。

首先考慮 b+c=zb+c=z 有多少種不同的分配方案數。很明顯有 z+1z+1 種分配方案,因此枚舉 aa,可以發現 a+b+c=za+b+c=z 的分配方案數爲 (z+1)+z+(z1)+...+1=(z+1)(z+2)2(z+1)+z+(z-1)+...+1 = \frac{(z+1)*(z+2)}{2}。當然也可以直接用組合數來求取答案,用隔板法可以得到總方案數爲 C(z+2,2)C(z+2,2),至此本題即可解決。


反思:

首先總結一下常見的幾個數學思維。
① 正難則反 —— 容斥思想、反演思想
② 變量思想 —— 設出未知量再不斷進行方程化簡,尋找規律

再總結一下此類數學思維題的一些經驗。
① 一道題拿到手上之後,一定要對問題不斷進行抽象化簡,不斷地深入思考,抽絲剝繭,逐層深入,纔有可能能夠解決這個問題。
② 要擅長去找到規律,從小例子上找到思路然後放到大例子上進行解決。

一個數學式子記錄。
a+b+c=zza+b+c = z,z 爲常數,一共有 C(z+2,2)C(z+2,2) 種 <a,b,ca,b,c> 分配方案。


代碼:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章