题目链接:点击这里
上来一顿贪心模拟,超时:
#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()函数判断
对脱水的时间进行二分,对于某次二分出来的值 :
- 对于含水量 的衣服,直接自然风干即可;
- 对于含水量
的衣服,最少的用时是用脱水机一段时间,自然风干一段时间,设这两段时间分别为
、
。那么有
,
。
联立两式可得: ,对这个式子向上取整就是脱干的最少用时(用于二分的判断)。
特殊情况,如果 的话直接输出最大的水分值就行。
#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;
}