【DTOJ】4042. KRUMPIRKO

题目描述

Young Mr. Potato is opening two new stores where he will, you guessed it, sell potatoes. Mr. Potato gets his potatoes from N farmers. Each farmer others exactly ai potatoes per bag for a total price of ci. Mr. Potato is going to buy all bags of potatoes from all farmers and place the bags in his two stores. Let’s denote the average potato price in the first store with P1, and the average potato price in the second store with P2. The average potato price in a store is equal to the ratio of the price and the total number of potatoes in the store. Taking into account logistical difficulties and the amount of potatoes in the stores, he wants the product of the average prices of potatoes in the stores to be minimal. In other words, he wants the product of P1 and P2 to be minimal.

After Mr. Potato settles on a division of bags in the stores, at least one store must have exactly L bags.

年轻的土豆先生开了两个新店,你猜对了,卖土豆。土豆先生从N个农民中获得土豆。每个农民提供土豆每袋ai个,这一袋土豆的价格是ci。土豆先生打算买所有农民的所有袋土豆放在他的两个商店。P1表示第一家店的土豆均价,P2表示第二家店的土豆均价。土豆的平均价格在商店里等于这个商店里所有袋的土豆的总价比上土豆的个数(不是袋数)。考虑到后勤方面的困难和土豆在商店里,他想要的产品平均价格的土豆在商店很小。换句话说,他想要的分配方案P1*P2是最小的。分配方案要求至少要有一个商店有恰好L袋土豆。

输入格式

The first line of input contains two integers N and L (2 <= N <= 100, 1 <= L < N), the number of potato bags and the number of potato bags in at least one store. The second line of input contains N integers ai (1 <= ai <= 100), separated by space. The third line of input contains N integers ci (1 <= ci <= 1000000), separated by space. The sum of all ai will be <= 500.

第一行包含两个整数N和L(2 < = N < = 100,1<=L<N)

第二行输入包含N个整数ai(1 < = ai< = 100),空格隔开。ai的总和<=500

第三行输入包含N个整数ci(1 < = ci < = 1000000),空格隔开。

输出格式

The first and only line of output must contain the minimal product of P1 and P2 from the task, rounded to three decimal places.

第一个也是唯一的输出包含最小的P1*P2,四舍五入到小数点后三位。

样例

样例输入1

3 1
3 2 1
1 2 3

样例输出1

0.556

样例输入2

3 2
2 2 2
3 3 3

样例输出2

2.250

数据范围与提示

SCORING In at least 30% of examples, it will hold N <= 20.


Solution

要使价值比个数的值最小,则价值应该尽量小,个数尽量多,则
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示考虑到第 i i i 袋,取了 j j j 袋,总共 k k k 个土豆时的最小价值,
则统计答案时,可以先枚举 k k k
则可以分成 f [ n ] [ l ] [ k ] f[n][l][k] f[n][l][k] f [ n ] [ n − l ] [ k ] f[n][n-l][k] f[n][nl][k] (P1取L个 或 P2取L个)两种情况分别计算该情况下的最值。

状态转移:
f [ i ] [ j ] [ k ] = { f [ i − 1 ] [ j ] [ k ]          ( k < a i ) min ⁡ ( f [ i − 1 ] [ j ] [ k ] , f [ i − 1 ] [ j − 1 ] [ k − a i ] + c [ i ] )          ( k ≥ a i ) f[i][j][k]=\begin{cases}f[i-1][j][k]\ \ \ \ \ \ \ \ (k<a_i)\\\\\min(f[i-1][j][k],f[i-1][j-1][k-a_i]+c[i])\ \ \ \ \ \ \ \ (k\ge a_i)\end{cases} f[i][j][k]=f[i1][j][k]        (k<ai)min(f[i1][j][k],f[i1][j1][kai]+c[i])        (kai)

初值: f [ i ] [ 0 ] [ 0 ] = 0 f[i][0][0]=0 f[i][0][0]=0

目标: min ⁡ 1 ≤ k < c n t { f [ n ] [ l ] [ k ] / k ∗ ( 价 值 和 − f [ n ] [ l ] [ k ] ) / ( 个 数 和 − k ) , f [ n ] [ n − l ] [ k ] / k ∗ ( 价 值 和 − f [ n ] [ n − l ] [ k ] ) / ( 个 数 和 − k ) } \min\limits_{1\le k<cnt}\{f[n][l][k]/k*(价值和-f[n][l][k])/(个数和-k),f[n][n-l][k]/k*(价值和-f[n][n-l][k])/(个数和-k)\} 1k<cntmin{f[n][l][k]/k(f[n][l][k])/(k),f[n][nl][k]/k(f[n][nl][k])/(k)}

可以利用滚动数组优化空间。

AC Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int N=105,INF=0x3f3f3f3f;

int n,l;
int a[N],c[N],f[N][505],value,cnt;
double ans=1e18;

int main()
{
	scanf("%d%d",&n,&l);
	for(register int i=1;i<=n;i++) scanf("%d",&a[i]),cnt+=a[i];
	for(register int i=1;i<=n;i++) scanf("%d",&c[i]),value+=c[i];
	memset(f,0x3f,sizeof f);
	f[0][0]=0;
	for(register int i=1;i<=n;i++)
		for(register int j=min(i,l);j>=1;j--)
			for(register int k=cnt;k>=a[i];k--)
				f[j][k]=min(f[j][k],f[j-1][k-a[i]]+c[i]);
	for(int k=1;k<cnt;k++)
	{
		if(f[l][k]!=INF) ans=min(ans,(double)(value-f[l][k])/(cnt-k)*f[l][k]/k);
		if(f[n-l][k]!=INF) ans=min(ans,(double)(value-f[n-l][k])/(cnt-k)*f[n-l][k]/k);
	}
	printf("%.3lf",ans);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值