一、一道繁瑣的大模擬
N個產品經理,M個程序員,P個需求。N個產品經理向M個程序員提出P個需求。
每個需求用四元組表示:產品經理ID(誰提出的) 提出時間 優先級(數字越大優先級越高) 需求開發時長
每個產品經理對於自己的需求按照:優先級從高到低、開發時長從短到廠、提出時間 從早到晚排序
每個程序員每次從產品經理最想做的需求里面挑選用時最短(如果時間相同優先做PM編號較小的需求)
求每個需求的完成時間。
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
class Idea {
int pm, think, use, pri, index;
int over;
Idea(int pm, int think, int pri, int use, int index) {
this.pm = pm;
this.think = think;
this.use = use;
this.pri = pri;
this.index = index;
}
@Override
public String toString() {
return "pm:" + pm + " think:" + think + " use" + use + " pri:" + pri;
}
}
class Pm {
PriorityQueue<Idea> ideas = new PriorityQueue<>((x, y) -> {
if (x.pri != y.pri) return -x.pri + y.pri;
if (x.use != y.use) return x.use - y.use;
return x.think - y.think;
});
boolean want(Idea i) {
return ideas.peek() == i;
}
}
class Programmer {
int time = 0;
}
Main() {
Scanner cin = new Scanner(System.in);
int PMCount = cin.nextInt(), ProgrammerCouunt = cin.nextInt(), IdeaCount = cin.nextInt();
Idea[] a = new Idea[IdeaCount];
Pm pms[] = new Pm[PMCount + 1];
for (int i = 0; i <= PMCount; i++) {
pms[i] = new Pm();
}
for (int i = 0; i < IdeaCount; i++) {
a[i] = new Idea(cin.nextInt(), cin.nextInt(), cin.nextInt(), cin.nextInt(), i);
}
PriorityQueue<Programmer> consumer = new PriorityQueue<>(Comparator.comparing(x -> x.time));
Arrays.sort(a, Comparator.comparingInt(x -> x.think));
int ai = 0;
PriorityQueue<Idea> producer = new PriorityQueue<>((x, y) -> {
if (x.use != y.use) return x.use - y.use;
return x.pm - y.pm;
});
for (int i = 0; i < ProgrammerCouunt; i++) consumer.add(new Programmer());
while (!producer.isEmpty() || ai < a.length) {
Programmer worker = consumer.poll();
if (producer.isEmpty()) {
worker.time = Math.max(a[ai].think, worker.time);
}
while (ai < a.length && a[ai].think <= worker.time) {
Idea task = a[ai++];
pms[task.pm].ideas.add(task);
producer.add(task);
}
Idea idea = producer.poll();
Pm pm = pms[idea.pm];
if (pm.want(idea)) {//如果當前idea是pm最想做的idea
pm.ideas.poll();//pm完成了這個任務
if (!pm.ideas.isEmpty()) producer.add(pm.ideas.peek());
worker.time = idea.over = Math.max(worker.time, idea.think) + idea.use;
// System.out.println("idea " + idea + " " + worker.time);
}
consumer.add(worker);
}
Arrays.sort(a, Comparator.comparingInt(x -> x.index));
for (Idea i : a) {
System.out.println(i.over);
}
}
public static void main(String[] args) {
new Main();
}
}
二、單調棧的變形應用
給定數組a[N],它有許多區間,求s=min(a[l:r]) \times sum(a[l:r])的最大值。a[N]中全為正整數。
sum(a[l:r])可以快速通過前綴和求出,因為要求s的最大值,所以區間[l:r]應該盡量大。但是又不能太大,因為太大的話,會使得min(a[l:r])很小。
對於a中的每個元素a[i],在保證a[i]為最小值得情況下,擴張左區間和右區間。問題轉化為快速求解a[i]左右第一個比它小的元素。
#include<iostream>
#include<stdio.h>
#include<map>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn = 5 * 1e5;
int n;
int a[maxn];
int s[maxn];
int lef[maxn], righ[maxn];//每個數字左邊比我小的和右邊比我小的
int getsum(int f, int t) {
if (t == 0)return s[f];
return s[t] - s[f - 1];
}
int main() {
cin >> n;
for (int i = 0; i < n; i++)scanf("%d", a + i);
int nows = 0;
for (int i = 0; i < n; i++) {
s[i] = nows + a[i];
nows += a[i];
}
stack<int>sta;
for (int i = 0; i < n; i++) {
while (!sta.empty()) {
int topIndex = sta.top();
int value = a[topIndex];
if (value > a[i]) {
sta.pop();
righ[topIndex] = i - 1;
}
else {
break;
}
}
int last = (sta.empty() ? 0 : sta.top() + 1);
lef[i] = last;
sta.push(i);
}
while (!sta.empty()) {
int topIndex = sta.top();
sta.pop();
righ[topIndex] = n - 1;
}
long long s = 0;
for (int i = 0; i < n; i++) {
s = max(s, getsum(lef[i], righ[i])*(long long)a[i]);
}
cout << s << endl;
return 0;
}
三、求邊界點
平面直角坐標系第一象限中包含一堆整數點,請找到全部滿足以下條件的點:(x,y)的左方、上方一個點也沒有。
這道題簡單的排序就能通過,但是因為數據量太大,用Java很容易超時,用C++ cin都會超時,必須用scanf才可以。
#include<iostream>
#include<stdio.h>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 5 * 1e5;
int n;
struct Point {
int x, y;
}a[maxn];
int b[maxn];
int bi;
bool com(const Point&one, const Point&two) {
if (one.x != two.x)return one.x<two.x;
else return one.y < two.y;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
}
sort(a, a + n, com);
bi = 0;
for (int i = 0; i < n; i++) {
if (i == n || a[i].x != a[i + 1].x) {
b[bi++] = i;
}
}
int ma = 0;
for (int i = bi - 1; i >= 0; i--) {
int ind = b[i];
if (ma > a[ind].y) {
b[i] = -1;
}
ma = max(ma, a[ind].y);
}
for (int i = 0; i < bi; i++) {
if (b[i] != -1) {
int ind = b[i];
cout << a[ind].x << " " << a[ind].y << endl;
}
}
return 0;
}
