woc, 13年前的ZJOI就这么毒瘤的嘛。。。
题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=1859
(luogu)https://www.luogu.org/problemnew/show/P2589
题解: 大分类讨论,预处理(ints[i][j])表示碗(i)叠在(j)上,(i)的底部比(j)的底部要高多少
然后分类讨论求此数组:
(1) (i)的下半径比(j)的上半径大,则等于(j)的高度
(2) (i)的上半径比(j)的下半径小,则等于零
(3) (i)的碗壁斜率大于(j)的碗壁斜率
(3.1) 若(i)的下半径小于等于(j)的下半径,则为零
(3.2) 若(i)的下半径大于(j)的下半径,则接触点横坐标为(i)的下半径,通过(j)的一次函数计算高度即可
(4) (i)的碗壁斜率小于(j)的碗壁斜率
(4.1) 若(i)的上半径大于等于(j)的上半径,则接触点为(j)的口处,通过(i)的一次函数计算高度
(4.2) 若(i)的上半径小于(j)的上半径,则(不妨先不考虑碗底)接触点横坐标为(i)的上半径,通过(j)的一次函数计算高度
情况(4)最后求出来的高度和(0)取Max.
(5) 若(i)和(j)碗壁斜率相等
(5.1) 若(i)的下半径小于等于(j)的下半径,则高度为(0).
(5.2) 若(i)的下半径大于(j)的上半径,则接触点横坐标为(i)的下半径,通过一次函数计算高度即可。
然后一个显然的性质是一个碗叠在一摞碗上,它的叠放高度为和每个碗分别叠放的高度的Max.
时间复杂度(O(n! imes n))
这题……我还能说什么呢23333
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<algorithm>
using namespace std;
const int N = 9;
struct Element
{
int h,r1,r2;
double calc(double x) {return h*(x-(double)r1)/((double)r2-r1);}
} a[N+3];
double hh[N+3];
int permu[N+3];
double ints[N+3][N+3];
int n;
double intersect(int x,int y)
{
// printf("Intersect (%d,%d)
",x,y);
double ret;
if(a[x].r1>a[y].r2) {ret = a[y].h;/* printf("Case 1
");*/}
else if(a[x].r2<a[y].r1) {ret = 0;/* printf("Case 2
");*/}
else if((a[y].r2-a[y].r1)*a[x].h>(a[x].r2-a[x].r1)*a[y].h)
{
if(a[x].r1<=a[y].r1) {ret = 0;/* printf("Case 3.1
");*/}
else {ret = a[y].calc((double)a[x].r1);/* printf("Case 3.2
");*/}
}
else if((a[y].r2-a[y].r1)*a[x].h<(a[x].r2-a[x].r1)*a[y].h)
{
if(a[x].r2>=a[y].r2) {ret = a[y].h-a[x].calc(a[y].r2);/* printf("Case 4.1
");*/}
// else if(a[x].h*(a[y].r2-a[y].r1)<=a[y].h*(a[x].r2-a[y].r1)) {ret = 0;}
else {ret = a[y].calc(a[x].r2)-a[x].calc(a[x].r2);/* printf("Case 4.2
");*/}
if(ret<0) ret = 0;
}
else
{
if(a[x].r1<=a[y].r1) {ret = 0;/* printf("Case 5.1
");*/}
else {ret = a[y].calc(a[x].r1);/* printf("Case 5.2
");*/}
}
// printf("ret=%lf
",ret);
return ret;
}
double calc()
{
// printf("calc: "); for(int i=1; i<=n; i++) printf("%d ",permu[i]); puts("");
double ret = 0.0;
for(int i=1; i<=n; i++)
{
hh[i] = 0;
for(int j=1; j<i; j++)
{
hh[i] = max(hh[i],hh[j]+ints[permu[i]][permu[j]]);
}
ret = max(ret,hh[i]+a[permu[i]].h);
}
// printf("Total=%lf
",ret); puts("");
return ret;
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d%d%d",&a[i].h,&a[i].r1,&a[i].r2);
for(int i=1; i<=n; i++) permu[i] = i;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i==j) continue;
ints[i][j] = intersect(i,j);
}
}
double ans = 1e6;
do
{
ans = min(ans,calc());
} while(next_permutation(permu+1,permu+n+1));
printf("%d
",(int)(ans+0.5));
return 0;
}