A
题意:给出n个节目的起止时间,问最多能完整看多少节目.
思路:贪心
三种想法:
1.根据开始时间对节目排序。但是开始时间早的不一定会被选择,无法判断当前节目该不该选
2.根据节目时长排序。但是短的不一定被选择,无法判断当前节目该不该选,比如:
4
1 10
1 5
6 10
4 6
3.根据结束时排序。如果选择当前节目,那么它一定是在可以选择的节目中结束时间最早的,可以得到局部最优解,以此类推得到整体最优。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int, int> pii;
int main() {
int n;
while (cin >> n && n) {
vector<pii> record;
for (int i = 0; i < n; i++) {
pii tem;
scanf("%d %d", &tem.second, &tem.first);
record.push_back(tem);
}
sort(record.begin(), record.end());// 按 节 目 结 束 时 间 排 序
int count = 0, lastend = -1;// 看 完 整 节 目 数 量 , 上 一 个 节 目 结 束 时 间
for (int i = 0; i < n; i++) {
if (record[i].second >= lastend) {
// 节 目 的 开 始 时 间 一 定 要 在 上 一 个 节 目 结 束 之 后
count++;
lastend = record[i].first;
}
}
printf("%d\n", count);
}
return 0;
}
B
题意:找满足阶乘有Q个0的最小N
思路:Q个0对应Q个5,找阶乘中有Q个5的最小值
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int T;
ll Q, l, r, m, t;
ll search(ll x) //计算x的阶乘中有几个5
{
ll cnt = 0;
while (x)
{
cnt += (x / 5);
x /= 5;
}
return cnt;
}
int main()
{
scanf("%d", &T);
for (int i = 1; i <= T; i++) //有T组测试用例
{
scanf("%lld", &Q);
l = 1, r = 1e10 + 10; //r的值需要开大一点
while (l < r)
{
m = (l + r) / 2;
if (search(m) >= Q) //>可能好理解一点,=Q还要r=mid是因为现在碰到的数不一定是最小的满足条件的数,因此还需要再找
{
t = m; //储存可行解
r = m; //r=mid是因为mid可能是满足条件的值,不能跳过
}
else
l = m + 1; //l=mid+1是因为mid不满足条件,直接把左端点移到mid后面一个就星
}
printf("Case %d: ", i);
if (search(t) == Q)
printf("%lld\n", t);
else
printf("impossible\n");
}
return 0;
}
C
题意:给出y的值,求使f(x)最小的x
思路:根据导数确定最小值的位置。f'(mid) < 0 则在 mid 右边取最小值, 否则在左边取最小值
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
double check1(double x, double y)
{
return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * x * x - y * x;
}
double check2(double x, double y)
{
return 42 * pow(x, 6) + 48 * pow(x, 5) + 21 * pow(x, 2) + 10 * x - y;
}
int main() {
double x;
int t;
cin >> t;
long long y;
double mid = 0;
while (t--) {
scanf("%lld", &y);
double l = 0, r = 100;
double ans = 0;
while (fabs(r - l) > 1e-6) {
mid = (l + r) / 2;
if (check2(mid, y) > 0) { r = mid; }
else { l = mid; }
}
printf("%.4lf\n", check1(l, y));
}
return 0;
}
D
题意:N个pei分给F+1个人,每个人得到的是每个pei完整的一部分,求每个人最大能分到多少
思路:二分,判断当前大小能不能分成F+1个,通过二分找到最大值
#include<iostream>
#include<algorithm>
#include<cstring>
#define pi acos(-1)
using namespace std;
int T, N, F, R;
double s[20000], x, sum, l, r;
int check(double mid) {
int z = 0;
for (int i = 1; i <= N; i++) {
z += (int)(s[i] / mid);
}
if (z >= F) return 1;
else return 0;
}
int main() {
cin >> T;
while (T--) {
cin >> N >> F;
F++;
for (int i = 1; i <= N; i++) {
cin >> x;
s[i] = pi * x * x;
sum += s[i];
}
l = 0.0;
r = sum / F;
double mid = 0;
while (fabs(l - r) > 1e-6) {
mid = (l + r) / 2;
if (check(mid)) { l = mid; }
else r = mid;
}
printf("%.4lf\n", l);
}
return 0;
}
E
题意:每次从字符串的左边或者右边选择较小的一个,组成字典序最小的字符串。
思路:左右不等,选小的。如果左边和右边相等,看起来是任选,但是需要考虑选择哪边的字符可以使较小的字符尽快被选到。
例:
CABBC
先选最后一个:CBBAC
先选第一个:CABBC
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int n;
int num = 0;
cin >> n;
char v[2005];
for (int i = 0; i < n; i++) {
cin >> v[i];
}
int l = 0;
n--;
while (l <= n) {
bool k = false;
for (int i = 0; i <= n - l; i++) {
if (v[l + i] < v[n - i]) {
k = true;//选左边
num++;
break;
}
else if (v[l + i] > v[n - i]) {
k = false;//选右边
num++;
break;
}
}
if (k)
cout << v[l++];
else
cout << v[n--];
if (num % 80 == 0)
cout << endl;
}
return 0;
}
G:二分加贪心
题意:一条长为l 的河中有n 块石头,仅可走m 次到河对岸,求所有可行方案中最大跳跃距离的最小值。
思路:设L为跳跃距离的最小值,R为最大值,根据MID是否成立进行区间收缩。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll s[1000000];
ll n,m,l;
ll minn=1000000000;
ll le,ri,ans,mid,cnt;
ll judge(ll a)
{
cnt=0;
ll midd=0;//记录中间值
for(int i=1;i<=n;i++)
if(s[i]-s[midd]<=a&&s[i+1]-s[midd]>a)
{
midd=i;
cnt++;
}
return ++cnt;//最后一步没有加上
}
int main()
{
while(cin>>l>>n>>m)
{
for(int i=1;i<=n;i++) scanf("%lld",&s[i]);//要用scanf,否则TL
s[0]=0;
s[n+1]=l;
sort(s,s+n+2);
ll maxn=0;
for(int i=1;i<=n+1;i++)
maxn=max(s[i]-s[i-1],maxn);//最小距离的最小值为两石头相隔距离的最大值
le=maxn,ri=l;
while(le<=ri)
{
mid=(le+ri)>>1;
if(judge(mid)<=m)
{
ans=mid;
ri=mid-1;//求最小距离
}
else le=mid+1;
}
cout<<ans<<endl;
}
return 0;
}