目录
思路篇
谷仓
题目描述
有一个圆形的谷仓,共有n个房间,按顺时针编号从1到n。现在有许多头奶牛,他们都有自己最喜欢的一个房间。傍晚回家时,奶牛们去找自己最喜欢的房间。如果发现被占了,他们就会按照顺时针方向找第一个空闲的房间住进去。现在请你输出最小的空闲的房间号。注意,这个答案和奶牛们回家的顺序是无关的。
2<=n<=3000000,1<=k<=10000,A,B的值在区间[0,10^9]。
输入
输入格式:
第一行两个整数n,k。
接下来有k行。每行4个整数,x,y,a,b.表示有x头奶牛喜欢f[1],f[2]……,f[y]。其中f[i]=(a*i+b)%n+1.
输出
输出格式:
输出最小的空闲房间号。
样例输入
10 3 3 2 2 4 2 1 0 1 1 1 1 7
样例输出
6
这道题,首先我们可以将F算出来,累计放在房间中,例如这个样例
第一次 f[1] = 7 f[2] = 9 0 0 0 0 0 0 3 0 3 0
第二次 f[1] = 2 0 2 0 0 0 0 3 0 3 0
第三次 f[1] = 9 0 2 0 0 0 0 3 0 4 0
好,我们的初始化就好了!
那怎么搞呢?
从后往前,找到最前面的空房间,压进去,这里不同于圆形谷仓,我们本来的位置是要留一头牛的,因为第一头牛肯定直接走喜欢的房间,不会向前找空房间
我们的队列就存房间编号吧(此思路是自己想的,好像和熊兄弟不一样,也许也不是最优)
que 10
当到 9 时,我们就踢牛到最前面的空房间 0 2 0 0 0 0 3 0 3 1
que 8
当到 7 时,我们又继续 0 2 0 0 0 2 1 3 1
que 6 5 4 3
当到 2 时,我们又继续(注意,队列尾部才是最近的空房间) 0 1 1 0 0 0 2 1 3 1
que 6 5 4 1
我们就完了!一样的,我们需要2圈,因为后面的奶牛也许会跑到前面去!
到10时,奶牛是1,不大于1,所以不用移动
到9时,开始操作 1 1 1 1 0 0 2 1 1 1 que 6 5
到6时,开始操作 1 1 1 1 1 0 2 1 1 1 que 6
然后再一个循环找就行了(我也不是很清楚队列里的队列尾部就是答案,大家可以尝试)
拥挤的奶牛
FJ的n头奶牛(1<=n<=50000)在被放养在一维的牧场。第i头奶牛站在位置x(i),并且x(i)处有一个高度值h(i)(1<=x(i),h(i)<=1000000000)。
一头奶牛感觉到拥挤当且仅当它的左右两端都有一头奶牛所在的高度至少是它的2倍,且和它的距离最多为D。尽管感到拥挤的奶牛会产生更少的牛奶,FJ还是想知道一共有多上感到拥挤的奶牛。请你帮助他。
输入
第一行:两个整数n和D。
第二行到第n+1行:每一行有两个数表示x(i)和h(i)。
输出
一个数k表示感到拥挤的奶牛的数量。
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
6 4 10 3 6 2 5 3 9 7 3 6 11 2
样例输出
2
我们肯定是用单调队列来维护他前面合法区间最高的牛啦,维护一个递减栈,如果最高的奶牛身高超过等于他的2倍,自然他的左边是有奶牛比他的身高高2倍的,那么怎么考虑右边,再反向一个就行啦,你也可以用一个bool数组来存储这个奶牛左边有没有比自己高2倍的,那么方向的时候,如果右边有,bool类型又恰好表明左边有,那么这个奶牛就感觉拥挤了!
弹簧高跷
在草场上有一条直线,直线上有若干个目标点。每个目标点都有一个分值和一个坐标。现在你可以选择其中任意一个目标点开始跳,只能沿一个方向跳,并且必须跳到另一个目标点。且每次跳的距离都不能少于上一次的距离。请问你能得到的最大分值是多少?
输入
第一行一个整数N(1<=N<=1000).接下来从第二行到第N+1行,每一行包含两个整数x(i)和p(i),每个整数在区间[0,1000000]之间。
输出
输出格式:最大能获得的分值。
6 5 6 1 1 10 5 7 6 4 8 8 10
样例输出
25
这道题我们是用DP做,我们设f[i][j]表示上一个阶段是从j跳到i的最大分数
那么我们可以知道 f[i][j] = max(f[i][j],f[j][k] + s[i]) x[j] - x[i] >= x[j] - x[k]
我们发现这里是三重循环,那么我们自然是要改变循环方向才可以做了
我们先考虑k在j的左边,i在j的右边,那么我们以j为第一层循环,k和i左右两边散开,和为一个数组的长度,这样就可以将一个三重循环优化为一个2重循环的时间复杂度了!
由于这上面的思路我们只考虑了一个方向,当然k也可以在j的右边,i在j的左边嘛,所以要正反做2次
i是要跳的,自然在j的左边或右边,那么上一个阶段的k,可不可以等于j,自然是可以的,那就是以j为起点嘛,所以k循环时,要把j==k的情况考虑。
我们还要预处理,即f[i][i] = s[i]
滑雪场的高度差
滑雪场可以看成M x N的网格状山地(1 <= M,N <= 500),每个网格是一个近似的平面,具有水平高度值在0 .. 1,000,000,000米的范围内。
某些网格被指定为关键网格。当两个相邻网格之间的高度差的绝对值不超过某个参数D时,就可以相互到达。相邻关系是指某个格子的东、西、南、北的格子。
显然,当D不断减小时,原本可以相互到达的相邻格子就不能到达了。
滑雪赛的组委会想知道,为了保证各个关键网格之间彼此连通,最小的D是多少?
输入
第1行:2个整数M和N
接下来M行,每行N个整数,表示各网格的高度
接下来M行,每行N个0或者1,1表示关键网格
输出
第1行:1个整数,表示最小的D
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
3 5 20 21 18 99 5 19 22 20 16 26 18 17 40 60 80 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1
样例输出
21
这道题是2分+bfs
2分自然是二分答案了,那么我们如何bfs?首先我们从任意一个关键网格出发,进行bfs(走到下一个点的条件比普通的走迷宫多了一个判断高度差的条件),队列为空后,我们看看,是不是所有的关键网格都走到了(如果是,那么说明关键网格互相可以连通,因为一个关键网格可以走到其他所有的关键网格,那么说明这个图至少有顶点的个数-1条边,构成了连通图)
我们要预处理,知道哪些是关键网格,这样就可以节省时间了!
代码篇
谷仓
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <list>
#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(int x){
if(x < 0){
putchar('-');
x *= -1;
}
if(x > 9){
write(x / 10);
}
putchar((x % 10) + '0');
}
long long n, k, a[3000005], x, y, afa, b;
list<long long> que;
int main(){
read(n);
read(k);
for(reg int i = 1; i <= k; i++){
read(x);
read(y);
read(afa);
read(b);
for(reg int j = 1; j <= y; j++){
a[(afa * j + b) % n + 1] += x;
}
}
for(reg int i = n; i >= 1; i--){
if(a[i] > 1){
while(a[i] > 1 && !que.empty()){
int t = que.back();
a[t] = 1;
a[i] --;
que.pop_back();
}
}
if(!a[i]) {
que.push_back(i);
}
}
for(reg int i = n; i >= 1; i--){
if(a[i] > 1){
while(a[i] > 1 && !que.empty()){
int t = que.back();
a[t] = 1;
a[i] --;
que.pop_back();
}
}
if(!a[i]) {
que.push_back(i);
}
}
for(reg int i = 1; i <= n; i++){
if(!a[i]){
write(i);
return 0;
}
}
}
拥挤的奶牛
#include <cstdio>
#include <algorithm>
#include <cstring>
#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 id, hi;
bool operator < (const node &rhs) const {
return id < rhs.id;
}
}a[50005];
int ans, n, d, que[50005], head, tail;
bool vis[50005];
int main(){
read(n);
read(d);
for(reg int i = 1; i <= n; i++){
read(a[i].id);
read(a[i].hi);
}
sort(a + 1, a + 1 + n);
head = tail = 1;
for(reg int i = 1; i <= n; i++){
while(head < tail){
if(a[i].id - a[que[head]].id > d){
head ++;
}
else {
break;
}
}
if(a[que[head]].hi >= a[i].hi * 2){
vis[i] = 1;
}
while(head < tail){
if(a[que[tail - 1]].hi < a[i].hi){
tail --;
}
else {
break;
}
}
que[tail] = i;
tail ++;
}
head = tail = 1;
memset(que, 0, sizeof(que));
for(reg int i = n; i >= 1; i--){
while(head < tail){
if(a[que[head]].id - a[i].id > d){
head ++;
}
else {
break;
}
}
if(a[que[head]].hi >= a[i].hi * 2 && vis[i]){
ans ++;
}
while(head < tail){
if(a[que[tail - 1]].hi < a[i].hi){
tail --;
}
else {
break;
}
}
que[tail] = i;
tail ++;
}
write(ans);
return 0;
}
弹簧高跷
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#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 x, id;
bool operator < (const node &rhs) const {
return id < rhs.id;
}
}a[1005];
int n, f[1005][1005], ans;
int main(){
read(n);
for(reg int i = 1; i <= n; i++){
read(a[i].id);
read(a[i].x);
}
sort(a + 1, a + 1 + n);
for(reg int j = 1; j <= n; j++){
f[j][j] = a[j].x;
ans = max(ans, f[j][j]);
for(reg int i = j + 1; i <= n; i++){
for(reg int k = j; k >= 1; k--){
if(a[i].id - a[j].id >= a[j].id - a[k].id){
f[i][j] = max(f[i][j], f[j][k] + a[i].x);
ans = max(ans, f[i][j]);
}
}
}
}
memset(f, 0, sizeof(f));
for(reg int j = n; j >= 1; j--){
f[j][j] = a[j].x;
ans = max(ans, f[j][j]);
for(reg int i = j - 1; i >= 1; i--){
for(reg int k = j; k <= n; k++){
if(a[j].id - a[i].id >= a[k].id - a[j].id){
f[i][j] = max(f[i][j], f[j][k] + a[i].x);
ans = max(ans, f[i][j]);
}
}
}
}
write(ans);
return 0;
}
滑雪场的高度差
#include <cstdio>
#include <queue>
#include <cstring>
#include <vector>
#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 x, y;
};
int n, m, h[505][505], dir[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};
bool vis[505][505];
queue<node> q;
vector<node> yes;
inline int csq(int x){
if(x < 0){
return -x;
}
return x;
}
inline bool bfs(int x){
while(!q.empty()){
q.pop();
}
memset(vis, 0, sizeof(vis));
node he;
he = yes[0];
vis[he.x][he.y] = 1;
q.push(he);
while(!q.empty()){
node t = q.front(), ne;
q.pop();
for(reg int i = 0; i < 4; i++){
ne.x = t.x + dir[i][0];
ne.y = t.y + dir[i][1];
if(!vis[ne.x][ne.y] && ne.x >= 1 && ne.x <= n && ne.y >= 1 && ne.y <= m && csq(h[ne.x][ne.y] - h[t.x][t.y]) <= x){
vis[ne.x][ne.y] = 1;
q.push(ne);
}
}
}
for(reg int i = 1; i < yes.size(); i++){
if(!vis[yes[i].x][yes[i].y]){
return 0;
}
}
return 1;
}
inline int ef(int l,int r){
while(l < r){
int mid = (l + r) >> 1;
if(bfs(mid)){
r = mid;
}
else {
l = mid + 1;
}
}
return l;
}
int main(){
read(n);
read(m);
for(reg int i = 1; i <= n; i++){
for(reg int j = 1; j <= m; j++){
read(h[i][j]);
}
}
int iop;
for(reg int i = 1; i <= n; i++){
for(reg int j = 1; j <= m; j++){
read(iop);
if(iop){
node he;
he.x = i;
he.y = j;
yes.push_back(he);
}
}
}
if(yes.empty()){
printf("0");
return 0;
}
int ans = ef(0, 1000000000);
write(ans);
return 0;
}