POJ 3104 Drying(迷之二分、数学)

题目链接:点击这里
在这里插入图片描述
在这里插入图片描述
上来一顿贪心模拟,超时:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<map>
#include<set>

using namespace std;
typedef long long ll;
const int MOD = 10000007;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 100010;
int n, a[maxn], k;

bool judge()
{
	for(int i = 0; i < n; i++)
		if(a[i]!=0)	return false;
	return true;
}

int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i++)
		scanf("%d", &a[i]);
	scanf("%d", &k);
	
	int cnt = 0;
	while(1)
	{
		sort(a, a+n);
		if(a[n-1] >= k)	a[n-1] -= k;	//最大的减k
		else	a[n-1] = 0;
		for(int i = 0; i < n-1; i++)	//其余的减1
			if(a[i]>=1)	a[i]--;
		cnt++;
		if(judge())	break;	//全部晒干就退出
	}
	printf("%d\n", cnt);
	return 0;
}

加一下大根堆优化感觉应该可以,还是超时:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<map>
#include<set>

using namespace std;
typedef long long ll;
const int MOD = 10000007;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 100010;
int n, k, x;

int main()
{
	priority_queue<int> q, tmp;
	scanf("%d", &n);
	for(int i = 0; i < n; i++)
	{
		scanf("%d", &x);
		q.push(x);
	}
	scanf("%d", &k);
	
	int cnt = 0;
	while(!q.empty())
	{
		x = q.top();
		q.pop();
		if(x > k)
		{
			x -= k;
			tmp.push(x);
		}
		
		while(!q.empty())
		{
			x = q.top();
			q.pop();
			if(x > 1)
			{
				x--;
				tmp.push(x);
			}
		}
		
		while(!tmp.empty())
		{
			q.push(tmp.top());
			tmp.pop();
		}
		cnt++;
	}
	printf("%d\n", cnt);
	return 0;
}

学长们还把题挂到了二分练习题里,找了半天单调性也没找到,这题跟二分有关系?!

没想到这道题竟然是用的二分,没想到二分还能这样用,哎,就感觉脑子不够用。

注意:难点在check()函数判断

对脱水的时间进行二分,对于某次二分出来的值 m i d mid

  1. 对于含水量 a i < = m i d a_i<=mid 的衣服,直接自然风干即可;
  2. 对于含水量 a i > m i d a_i>mid 的衣服,最少的用时是用脱水机一段时间,自然风干一段时间,设这两段时间分别为 x 1 x_1 x 2 x_2 。那么有 x 1 + x 2 = m i d x_1+x_2=mid a i < = k x 1 + x 2 a_i<=k∗x_1+x_2
    联立两式可得: x 1 > = ( a i m i d ) / ( k 1 ) x_1>=(a_i−mid)/(k−1) ,对这个式子向上取整就是脱干的最少用时(用于二分的判断)。

特殊情况,如果 k = 1 k=1 的话直接输出最大的水分值就行。

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<map>
#include<set>

using namespace std;
typedef long long ll;
const int MOD = 10000007;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 100010;
ll n, k, a[maxn];

bool check(ll mid)
{
	ll sum = 0;
    for(int i = 0; i < n; i++)
        if(a[i] > mid)
            sum += ceil((a[i]-mid)*1.0/(k-1));   //向上取,返回大于或者等于指定表达式的最小整数
    
    return sum <= mid;
}

int main()
{
	scanf("%lld", &n);
	ll maxx = 0;
	for(int i = 0; i < n; i++)
	{
		scanf("%lld", &a[i]);
		if(a[i] > maxx)	maxx = a[i];
	}
	scanf("%lld", &k);
	
	if(k==1)
	{
		printf("%lld\n", maxx);
		return 0;
	}
	
	ll left = 0, right = maxx, mid, ans;
	while(left<=right)
	{
		mid = left+(right-left)/2;
		if(check(mid))
		{
			ans = mid;
			right = mid - 1;
		}
		else
			left = mid + 1;
	}
	printf("%lld\n", ans);
	return 0;
}
发布了694 篇原创文章 · 获赞 104 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/104074998