目录
思路篇
测量温度
题目描述
某国进行了连续N(1<=N<=1000000)天的温度测量,测量存在误差,测量结果是第i天温度在[l_i,r_i]范围内。其中-10^9<l_i<=r_i<=10^9
求最长的连续的一段,满足该段内可能温度不降。
输入
第一行一个整数n。
接下来n行,每一行两个整数,表示l_i和r_i。
输出
接下来输出一个整数,表示答案。
输入样例
6
6 10
1 5
4 8
2 5
6 8
3 5
输出样例
4
大家也许会想到这样一个贪心,大家都知道,下一天的温度上限如果要低于昨天的可能温度,那么肯定是不可以的,所以今天的温度干脆直接等于下限算了,重新来一次,但是这很明显是错误的,我们可以举反例的(你们自己举吧!)
大家可能还不是很理解这个错误的思路(不理解也没关系,反正是错误的嘛),但我将代码给出你就明白了!
struct node{
int l, r;
}a[1000005];
int n, ans = 1, iop = 1;
int main(){
read(n);
for(reg int i = 1; i <= n; i++){
read(a[i].l);
read(a[i].r);
}
int tem = a[1].l;
for(reg int i = 2; i <= n; i++){
if(a[i].r >= tem){
iop ++;
if(a[i].l > tem){
tem = a[i].l;
}
}
else {
ans = max(ans, iop);
iop = 1;
tem = a[i].l;
}
}
ans = max(ans, iop);
write(ans);
return 0;
}
我们刚刚也说了,如果当天的上限温度比前面的一天的下限还要低,那么这两个是不可能会连续的(在一个符合要求的区间内),所以当天应该找到前面某一天的下限温度要小于等于自己的上限温度,这样他们才能在一个符合要求的区间内。
但是,仅仅考虑小于等于自己的上限温度是不行的,因为我们还要保证他们两个之间的天数中,没有一个下限温度比当前温度的上限温度还要大,不然,那个小于等于延伸过来后,温度就被下限温度比当前上限温度大的那一天提起来了,就不可能符合题意。
所以,我们如果知道了最大下限温度是第x天,并且保证最大的下限温度要低于当前的上限温度,也就是找到最大的下限温度且保证比当前的上限温度小,用一个单调队列来维护下限温度递减队列。
当然,他们之间的元素肯定也要保证上限温度比前一天的下限温度大!通过比较对头元素来保证这个条件!
我们发现,队列中只有符合较大的下限温度低于当前上限温度的那一天到当前这一天的元素,而之前的(即那一天的前面也可以延伸的部分)没有算,那应该是哪一部分?即为head前被踢出的元素,而之间的没有。那么说明没有被踢出去,只是被覆盖了,所以就是当前的位置减去que[head - 1]
不明白,建议你那代码去调试!
奶牛慢跑
题目描述
有n(n<=100000)头奶牛在一个无穷长的小道上慢跑。每头奶牛的起点不同,速度也不同。小道可以被分成多条跑到。奶牛只能在属于自己的跑道上慢跑,不允许更换跑道,也不允许改变速度。如果要慢跑t(t<=1000000000)分钟,要保证在任何时候不会有同一跑道上的奶牛相遇,请问最少需要多少条跑道。奶牛开始在哪条跑道是可以随意设置的。
输入
输入格式:第一行两个整数n,t。
接下来的n行,每行包含两个整数,表示奶牛的位置和速度。位置是非负整数,速度是正整数。所有的奶牛的起点都不相同,按起点递增的顺序给出。
输出
输出格式:
最少的跑道数。
样例输入
5 3
0 1
1 2
2 3
3 2
6 1
样例输出
3
为什么?我们先算出每一个奶牛跑完后的位置,那么本来在前面的(位置小的),结果位置还在后面了,就说明他超越了一些奶牛,那么这样,这个奶牛是不能和这些奶牛在一个跑道的。一个不上升子序列的长度,对于里面的奶牛,互相都不能在一个跑道上,也就需要这个序列长度这么多个跑道了,自然也就是求最长不上升子序列。
我们朴素的算法DP是O(n*n)的时间复杂度,所以肯定是不行的。
当然,有一种O(n*logn)的算法
为了让大家好理解,我们先看最长上升子序列。如果一个元素,找到了前面元素中第一个比自己大于等于的数,那么我们将这个数替换掉,那么这个序列依然满足上升,并且我们也知道了如果以当前这个元素结尾的最长上升子序列也就是他去替换的位置。
我们既计算好了当前元素结尾的最长上升子序列的长度,也为后面更长做了铺垫,因为你比原来的数小,所以上升的空间也可能会更大!
前面的元素是上升的,所以是有序的,我们二分就可以找到第一个比自己大于等于的位置了!时间就是O(n*logn)
那么最长不上升子序列,其实也是一样的思想,只不过我们找的是第一个小于自己元素的位置罢了!
路径规划
题目描述
有n个点,m条无向边,有A,B两个人,初始时刻A在点1,B在点2,他们要走到点n去。A每走一条边,要消耗B单位能量,B每走一条边,要消耗E单位能量。如果A,B相伴走,则只消耗P单位的能量。请问A,B走到点n,最少要消耗多少能量?
输入数据保证1和n,2和n连通。
输入
第一行包含整数B,E,P,N和M,所有的整数都不超过40000,N>=3.
接下来M行,每行两个整数,表示该无向边连接的两个顶点。
输出
一个整数,表示最小要消耗的能量。
样例输入
4 4 5 8 8
1 4
2 3
3 4
4 7
2 5
5 6
6 8
7 8
样例输出
22
我们自然想让他们会合,这样就可以让他们的花费最小了
用三次单源点最短路,求出1到所有点的最短路,2到所有点的最短路,点N到所有点的最短路
枚举他们在哪里会合,花费就是dis1[i]+dis2[i]+disn[i]
你会说他们可以不会合呀,我们枚举是可以考虑的,就是dis1[n]+dis2[n]+disn[n]
这个思想也是很好理解的!
奶牛飞盘
题目描述
有n(2<=n<=20)头奶牛在玩飞盘,可是飞盘飞到了高处。现在他们要想办法叠在一起,去取飞盘。飞盘的高度为H(1 <= H <= 1,000,000,000)。给出每头奶牛的重量、高度、强壮度(能够承受的重量),问他们是否够得到,如果能够取到,求它们额外还能承受最多多少重量。(要保证每头奶牛所承受的重量都不超过它的强壮度)。
输入
输入格式:
第一行包含N和H。
接下来N行,每行三个数,分别表示它的高度、重量和强壮度。所有的数都为正整数。
输出
输出格式:
如果奶牛的队伍可以够到飞盘,输出还能承受的最大额外重量;否则输出“Mark is too tall”.
输入样例
4 10
9 4 1
3 3 5
5 5 10
4 4 5
输出样例
2
这道题其实本质就是贪心加爆搜,我们贪心肯定要排序吧!
按照什么排序呢?按照强壮度加重量排序!
为什么呢?我们假设现在有一些牛,它们的最大承受度是IOP,那么,我们把第i头奶牛先放,再放第j头奶牛,那么承受度就是
min(IOP - w[i] - w[j],c[i] - w[j]),如果先放j,再放i,就是min(IOP - w[i] - w[j],c[j] - w[i])
其实就是要求max(c[i] - w[j],c[j] - w[i]) 我们移项,就是比较max(c[i] + w[i],c[j] + w[j])了,自然,c[i] + w[i]大的要放在下面,这样我们就确定了顺序,那要放哪些奶牛呢?爆搜dfs啊!恩恩恩!
代码篇
请慎重观看!
测量温度
#include <cstdio>
#include <iostream>
#define reg register
using namespace std;
inline void read(int &x){
int f = 1;
x = 0;
char s = getchar();
while(s < '0' || s > '9'){
if(s == '-'){
f = -1;
}
s = getchar();
}
while(s >= '0' && s <= '9'){
x = (x << 3) + (x << 1) + (s - '0');
s = getchar();
}
x *= f;
}
inline void write(int x){
if(x < 0){
putchar('-');
x *= -1;
}
if(x > 9){
write(x / 10);
}
putchar((x % 10) + '0');
}
struct node{
int l, r;
}a[1000005];
int n, ans = 1, iop = 1, que[1000005], head, tail;
int main(){
read(n);
for(reg int i = 1; i <= n; i++){
read(a[i].l);
read(a[i].r);
}
head = tail = 1;
que[tail ++] = 1;
for(reg int i = 2; i <= n; i++){
while(head < tail){
if(a[i].r < a[que[head]].l){
head ++;
}
else {
iop = i - que[head - 1];
break;
}
}
ans = max(ans, iop);
while(head < tail){
if(a[i].l > a[que[tail - 1]].l){
tail --;
}
else {
break;
}
}
que[tail ++] = i;
}
write(ans);
return 0;
}
奶牛慢跑
#include <cstdio>
#include <iostream>
#include <algorithm>
#define reg register
using namespace std;
inline void read(long long &x){
long long f = 1;
x = 0;
char s = getchar();
while(s < '0' || s > '9'){
if(s == '-'){
f = -1;
}
s = getchar();
}
while(s >= '0' && s <= '9'){
x = (x << 3) + (x << 1) + (s - '0');
s = getchar();
}
x *= f;
}
inline void write(long long x){
if(x < 0){
putchar('-');
x *= -1;
}
if(x > 9){
write(x / 10);
}
putchar((x % 10) + '0');
}
long long t, n, a[100005], g[100005], x, y, ans;
long long lower_bound_csq(int wei, long long csqx){
int l = 1, r = wei;
while(l < r){
int mid = (l + r) / 2;
if(g[mid] >= csqx){
l = mid + 1;
}
else {
r = mid;
}
}
return l;
}
int main(){
read(n);
read(t);
for(reg int i = 1; i <= n; i++){
read(x);
read(y);
a[i] = x + t * y;
g[i] = -(ans << 60);
}
long long k;
for(reg int i = 1; i <= n; i++){
k = lower_bound_csq(i, a[i]);
g[k] = a[i];
ans = max(ans, k);
}
write(ans);
return 0;
}
路径规划
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define reg register
using namespace std;
inline void read(int &x){
int f = 1;
x = 0;
char s = getchar();
while(s < '0' || s > '9'){
if(s == '-'){
f = -1;
}
s = getchar();
}
while(s >= '0' && s <='9'){
x = (x << 3) + (x << 1) + (s - '0');
s = getchar();
}
x *= f;
}
inline void write(int x){
if(x < 0){
putchar('-');
x *= -1;
}
if(x > 9){
write(x / 10);
}
putchar((x % 10) + '0');
}
bool vis[40005];
int b, e, p, n, m, x, y, ans, dis1[40005], dis2[40005], dis[40005];
vector<int> G[40005];
queue<int> q;
int main(){
read(b);
read(e);
read(p);
read(n);
read(m);
for(reg int i = 1; i <= m; i++){
read(x);
read(y);
G[x].push_back(y);
G[y].push_back(x);
}
memset(dis1, 0x3f, sizeof(dis1));
memset(dis2, 0x3f, sizeof(dis2));
q.push(1);
vis[1] = 1;
dis1[1] = 0;
while(!q.empty()){
int t = q.front();
q.pop();
vis[t] = 0;
for(reg int i = 0; i < G[t].size(); i++){
if(dis1[G[t][i]] > dis1[t] + 1){
dis1[G[t][i]] = dis1[t] + 1;
if(!vis[G[t][i]]){
vis[G[t][i]] = 1;
q.push(G[t][i]);
}
}
}
}
memset(vis, 0, sizeof(vis));
q.push(2);
dis2[2] = 0;
vis[2] = 1;
while(!q.empty()){
int t = q.front();
q.pop();
vis[t] = 0;
for(reg int i = 0; i < G[t].size(); i++){
if(dis2[G[t][i]] > dis2[t] + 1){
dis2[G[t][i]] = dis2[t] + 1;
if(!vis[G[t][i]]){
vis[G[t][i]] = 1;
q.push(G[t][i]);
}
}
}
}
if(b + e <= p){
ans = dis1[n] * b + dis2[n] * e;
write(ans);
}
else {
memset(vis, 0, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
q.push(n);
vis[n] = 1;
dis[n] = 0;
while(!q.empty()){
int t = q.front();
q.pop();
vis[t] = 0;
for(reg int i = 0; i < G[t].size(); i++){
if(dis[G[t][i]] > dis[t] + 1){
dis[G[t][i]] = dis[t] + 1;
if(!vis[G[t][i]]){
vis[G[t][i]] = 1;
q.push(G[t][i]);
}
}
}
}
ans = 2147483647;
for(reg int i = 1; i <= n; i++){
ans = min(ans, dis1[i] * b + dis2[i] * e + dis[i] * p);
}
write(ans);
}
return 0;
}
奶牛飞盘
#include <cstdio>
#include <algorithm>
#define reg register
using namespace std;
inline void read(long long &x){
long long f = 1;
x = 0;
char s = getchar();
while(s < '0' || s > '9'){
if(s == '-'){
f = -1;
}
s = getchar();
}
while(s >= '0' && s <= '9'){
x = (x << 3) + (x << 1) + (s - '0');
s = getchar();
}
x *= f;
}
inline void write(long long x){
if(x < 0){
putchar('-');
x *= -1;
}
if(x > 9){
write(x / 10);
}
putchar((x % 10) + '0');
}
struct node{
long long w, h, q;
bool operator < (const node &rhs) const {
return w + q < rhs.w + rhs.q;
}
}a[25];
long long n, wanth, sumh, sumw, maxq, ans = -1;
void dfs(int x){
if(x > n){
if(sumh >= wanth){
if(maxq > ans){
ans = maxq;
}
}
return ;
}
if(a[x].q >= sumw){
long long room = maxq;
if(a[x].q - sumw < maxq){
maxq = a[x].q - sumw;
}
sumh += a[x].h;
sumw += a[x].w;
dfs(x + 1);
sumh -= a[x].h;
sumw -= a[x].w;
maxq = room;
}
dfs(x + 1);
}
int main(){
maxq = 1 << 30;
read(n);
read(wanth);
for(reg int i = 1; i <= n; i++){
read(a[i].h);
read(a[i].w);
read(a[i].q);
}
sort(a + 1, a + 1 + n);
dfs(1);
if(ans == -1){
printf("Mark is too tall");
}
else {
write(ans);
}
return 0;
}