8.17日二分测试总结
8.17日二分测试总结
分数情况
| A.砍树 | B.买木头 | C.数列分段2 | D.吃冰棍 | E.跳石头 | F.奶牛晒衣服 |
|---|---|---|---|---|---|
| 100 | 80 | 100 | \(_{没做:(}\) | 10 | 0 |
总体分数

\(_{很惨}\)
T1. P1873 [COCI 2011/2012 #5] EKO / 砍树
题目传送门
问题分析
运用二分答案与
check函数
check函数用来检测答案是否合法
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6 + 7;
int n, m;
int a[maxn];
bool check(int x)
{
int ans = 0;
for (int i = 1; i <= n; ++i)
{
if (a[i] > x)
{
ans += (a[i] - x);
}
}
return ans >= m;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int maxx = 0;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
maxx = max(maxx, a[i]);
}
int l = 1, r = maxx + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
cout << l << "\n";
return 0;
}
T2. B3880 [信息与未来 2015] 买木头
题目传送门
\(Wrong\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn], b[maxn];
int n, m;
bool check(int x)
{
int sum = 0;
for (int i = 1; i <= n; ++i)
{
sum += a[i] / x * b[i];
if (sum >= m)
{
return 1;
}
}
return 0;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> a[1] >> b[1];
int maxx = INT_MIN;
for (int i = 2; i <= m; ++i)
{
a[i] = ((a[i - 1] * 37011 + 10193) % 10000) + 1;
b[i] = ((b[i - 1] * 73011 + 24793) % 100) + 1;
maxx = max(a[i], maxx);
}
int l = 0, r = maxx + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
cout << l << "\n";
return 0;
}
/*
10 10000 8 20
*/
问题分析
通过题目给的两个公式:
- \(l_i=((l_{i-1}\times37011+10193) \bmod 10000)+1\)
- \(s_i=((s_{i-1}\times73011+24793) \bmod 100)+1\)
和给出的初始值求出后面的每个数的大小
通过二分答案与
check函数查找合法的答案
错误分析
- 细节决定成败
题目中说:
一行四个整数 \(n,m,l_1,s_1\)。其中 \(l_1\) 是第一个供货商木头的长度,\(s_1\) 是第一个供货商木头的数量。
而我的输入为什么是 \(m\) !!! \(_{气死我了}\)
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn], b[maxn];
int n, m;
bool check(int x)
{
int sum = 0;
for (int i = 1; i <= n; ++i)
{
sum += a[i] / x * b[i];
if (sum >= m)
{
return 1;
}
}
return 0;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> a[1] >> b[1];
int maxx = INT_MIN;
for (int i = 2; i <= n; ++i)
{
a[i] = ((a[i - 1] * 37011 + 10193) % 10000) + 1;
b[i] = ((b[i - 1] * 73011 + 24793) % 100) + 1;
maxx = max(a[i], maxx);
}
int l = 0, r = maxx + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
cout << l << "\n";
return 0;
}
/*
10 10000 8 20
*/
T3. P1182 数列分段 Section II
题目传送门
前置题目 P1181 数列分段 Section I
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn];
int n, m;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int sum = 0, ans = 1;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
if (sum + a[i] <= m)
{
sum += a[i];
}
else
{
ans++;
sum = a[i];
}
}
cout << ans << "\n";
return 0;
}
回到正题(P1182)
使用P1181的大部分代码作为P1182的
check函数
具体代码如下
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int n, m;
int a[maxn];
bool check(int x)
{
int cnt = 1;
int sum = 0;
for (int i = 1; i <= n; ++i)
{
if (sum + a[i] <= x)
{
sum += a[i];
}
else
{
cnt++;
sum = a[i];
}
}
return cnt <= m;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int num = 0;
int maxx = 0;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
maxx = max(maxx, a[i]);
num += a[i];
}
int l = maxx - 1;
int r = num + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
cout << r << "\n";
return 0;
}
/*
5 3
4 2 4 5 1
*/
T4. B3629 吃冰棍
题目传送门
\(Wrong\) \(Code:\)
问题分析
做的时候想的是用模拟 \(+\) 枚举
题目说是二分
但是二分没有想到怎么做 😦
买的冰棍越多,剩余的木棍越多,
兑换的冰棍也会越多 冰棍的总数也会越多
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int n;
bool check(int x)
{
int cnt = x;
int sum = x;
while (cnt >= 3)
{
int tmp = cnt / 3;
cnt = cnt % 3;
sum += tmp;
cnt += tmp;
}
return sum >= n;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
int l = 1 - 1;
int r = n + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
cout << r << "\n";
return 0;
}
T5. P2678 [NOIP2015 提高组] 跳石头
题目传送门
\(Wrong\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn];
int lenn, num, m;
bool check(int x)
{
int res = a[1];
int sum = 1;
for (int i = 2; i <= num; ++i)
{
if (a[i] - res <= x)
{
res = a[i];
sum++;
}
}
if (lenn - a[num] <= x)
{
sum++;
}
if (a[1] - 1 <= x)
{
sum++;
}
return sum <= m;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> lenn >> num >> m;
for (int i = 1; i <= num; ++i)
{
cin >> a[i];
}
int l = 0;
int r = lenn + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
if (check(r))
{
cout << l << "\n";
}
else
{
cout << r << "\n";
}
return 0;
}
\(_{只过了样例和\#1}\) \(_{:(}\)
问题分析
最多移走块石头, \(l\) 代表两块石头的最近距离
如果两块石头之间的距离小于 \(l\) ,说明这块石头要被搬走
二分的答案就是 \(l\) , \(l\) 越大,满足要求的石头更少
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 7;
int L, n, m;
int a[maxn];
bool check(int mid)
{
int cnt = 0;
int now = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] - a[now] < mid)
{
cnt++;
}
else
{
now = i;
}
}
if (L - a[now] < mid)
{
cnt++;
}
return cnt <= m;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> L >> n >> m;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
}
int l = 0;
int r = L + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
cout << l << "\n";
return 0;
}
T6. P1843 奶牛晒衣服
\(_{题面有意思:)}\)
问题分析
用二分与
check两个老朋友但是
r要足够大!!!我用的是 \(5000 \times 5000 + 1\)
如果能够在 \(mid\) 时间内烘干.
将右区间缩小
注意: 要开
long long
\(AC\) \(Code:\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 5e5 + 7;
int w[maxn];
int n, a, b;
bool check(int x)
{
int t = 0;
for (int i = 1; i <= n; i++)
{
int tmp = w[i] - a * x;
if (tmp > 0)
{
t += ceil(tmp * 1.0 / b);
}
}
return t <= x;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> a >> b;
for (int i = 1; i <= n; ++i)
{
cin >> w[i];
}
int l = 0;
int r = 5000 * 5000 + 1;
while (l + 1 < r)
{
int mid = (l + r) / 2;
if (check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
cout << r << "\n";
return 0;
}
\(\mathbb {THE\ END}\)
本文来自博客园,作者:yucheng0630,转载请注明原文链接:https://www.cnblogs.com/yucheng0630/p/18365442

浙公网安备 33010602011771号