考試(二)(標題未取好)
目錄
思路篇
測量溫度
題目描述
某國進行了連續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;
}