今天写了补题
# [蓝桥杯 2018 省 AB] 全球变暖
## 题目描述
你有一张某海域 $N \times N$ 像素的照片,`.` 表示海洋、 `#` 表示陆地,如下所示:
```
.......
.##....
.##....
....##.
..####.
...###.
.......
```
其中 "上下左右" 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 $2$ 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
```
.......
.......
.......
.......
....#..
.......
.......
```
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
## 输入格式
第一行包含一个整数 $N$。$(1 \le N \le 1000)$。
以下 $N$ 行 $N$ 列代表一张海域照片。
照片保证第 $1$ 行、第 $1$ 列、第 $N$ 行、第 $N$ 列的像素都是海洋。
## 输出格式
一个整数表示答案。
## 样例 #1
### 样例输入 #1
```
7
.......
.##....
.##....
....##.
..####.
...###.
.......
```
### 样例输出 #1
```
1
```
## 提示
时限 1 秒, 256M。蓝桥杯 2018 年第九届省赛
最蠢的思路
1先找总共的岛屿数量2再找还剩余的岛屿数量3再相见就好
有些人会疑问为什么要这么麻烦,别问问就是我TM吧题目本意看错了看成还剩余岛屿的数量想着不能前功尽弃就这样玩了(这告诉我们一定要看清楚题目)
1找全部岛屿的数量找到#以此陆地的ij为起点进行层层搜索搜到一块相连的陆地就将其标记起来
因此与#相连的不会再次搜索num也只会加一次,机智如我
void bfs1(int i,int j)
{
struct li e[100000];
int head=1;
int tail=1;
book3[i][j]=1;
e[tail].x=i;
e[tail].y=j;
tail++;
while(head<tail)
{
int tx,ty;
for(int k=0;k<4;k++)
{
tx=e[head].x+dir[k][0];
ty=e[head].y+dir[k][1];
if(tx<1||ty<1||tx>n||ty>n)
continue;
if(a[tx][ty]=='#'&&book3[tx][ty]==0)
{
e[tail].x=tx;
e[tail].y=ty;
book3[tx][ty]=1;
tail++;
}
}
head++;
}
memset(e,0,sizeof(e));
}
int num=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]=='#'&book3[i][j]==0)
{
bfs1(i,j);
num++;
}
}
}
2还剩余岛屿的数量
如果ij不相邻就将所有不相邻的陆地标记起来从这些被标记了的内陆进行岛搜索,所搜过程与搜索岛屿过程一模一样就是多了个要在内陆搜索的条件sum表总数量
void bfs(int i,int j){
struct li m[100000];
int head=1;
int tail=1;
book2[i][j]=1;
m[tail].x=i;
m[tail].y=j;
tail++;
while(head<tail)
{
int tx,ty;
for(int k=0;k<4;k++)
{
tx=m[head].x+dir[k][0];
ty=m[head].y+dir[k][1];
if(tx<1||ty<1||tx>n||ty>n)
continue;
if(a[tx][ty]=='#'&&book2[tx][ty]==0)
{
m[tail].x=tx;
m[tail].y=ty;
book2[tx][ty]=1;
tail++;
}
}
head++;
}
memset(m,0,sizeof(m));
}
int sum=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(book1[i][j]==1&&book2[i][j]!=1)
{
bfs(i,j);
sum++;
}
}
}
3将两数相减及num-sum
总代码为:
#include<bits/stdc++.h>
using namespace std;
struct li{
int x;
int y;
};
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
char a[100][100];
int book1[100][100]={0};
int book2[100][100]={0};
int book3[100][100]={0};
int n;
void bfs(int i,int j){
struct li m[100000];
int head=1;
int tail=1;
book2[i][j]=1;
m[tail].x=i;
m[tail].y=j;
tail++;
while(head<tail)
{
int tx,ty;
for(int k=0;k<4;k++)
{
tx=m[head].x+dir[k][0];
ty=m[head].y+dir[k][1];
if(tx<1||ty<1||tx>n||ty>n)
continue;
if(a[tx][ty]=='#'&&book2[tx][ty]==0)
{
m[tail].x=tx;
m[tail].y=ty;
book2[tx][ty]=1;
tail++;
}
}
head++;
}
memset(m,0,sizeof(m));
}
void bfs1(int i,int j)
{
struct li e[100000];
int head=1;
int tail=1;
book3[i][j]=1;
e[tail].x=i;
e[tail].y=j;
tail++;
while(head<tail)
{
int tx,ty;
for(int k=0;k<4;k++)
{
tx=e[head].x+dir[k][0];
ty=e[head].y+dir[k][1];
if(tx<1||ty<1||tx>n||ty>n)
continue;
if(a[tx][ty]=='#'&&book3[tx][ty]==0)
{
e[tail].x=tx;
e[tail].y=ty;
book3[tx][ty]=1;
tail++;
}
}
head++;
}
memset(e,0,sizeof(e));
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
int num=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]=='#'&book3[i][j]==0)
{
bfs1(i,j);
num++;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]=='#')
{
if(a[i-1][j]!='.'&&a[i][j-1]!='.'&&a[i+1][j]!='.'&&a[i][j+1]!='.')
{
book1[i][j]=1;
}
}
}
}
int sum=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(book1[i][j]==1&&book2[i][j]!=1)
{
bfs(i,j);
sum++;
}
}
}
cout<<num-sum<<endl;
}
# [蓝桥杯 2018 省 B] 日志统计
## 题目描述
小明维护着一个程序员论坛。现在他收集了一份“点赞”日志,日志共有 $N$ 行。其中每一行的格式是 `ts id`,表示在 $ts$ 时刻编号 $id$ 的帖子收到一个“赞”。
现在小明想统计有哪些帖子曾经是“热帖”。如果一个帖子曾在任意一个长度为 $D$ 的时间段内收到不少于 $K$ 个赞,小明就认为这个帖子曾是“热帖”。
具体来说,如果存在某个时刻 $T$ 满足该帖在 $[T,T+D)$ 这段时间内(注意是左闭右开区间)收到不少于 $K$ 个赞,该帖就曾是“热帖”。
给定日志,请你帮助小明统计出所有曾是“热帖”的帖子编号。
## 输入格式
第一行包含三个整数 $N$、$D$ 和 $K$。
以下 $N$ 行每行一条日志,包含两个整数 $ts$ 和 $id$。
## 输出格式
按从小到大的顺序输出热帖 $id$。每个 $id$ 一行。
## 样例 #1
### 样例输入 #1
```
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
```
### 样例输出 #1
```
1
3
```
## 提示
对于 $50\%$ 的数据,$1 \le K \le N \le 1000$。
对于 $100\%$ 的数据,$1 \le K \le N \le 10^5$,$0 \le id, ts \le 10^5$。
时限 1 秒, 256M。蓝桥杯 2018 年第九届省赛
单调队列问题
还记得单调队列滑动窗口问题吗
这个根据时间进行排序,那窗口是啥尼就是这个t(时间)在这个窗口中若相同id出现次数超过m次就代表是热贴相同id出现次数咋表示泥a[ma[i].x]++;ma[i].x存折的就是id嘛
#include <bits/stdc++.h>
using namespace std;
struct li {
int t;//时间
int x;//id
};
void quicksort(struct li ma[], int left, int right) {
if (left >= right) return;
int i = left, j = right, t;
struct li temp = ma[left];
t = ma[left].t;
while (i != j) {
while (ma[j].t >= t && i < j) j--;
while (ma[i].t <= t && i < j) i++;
if (i < j) {
swap(ma[i], ma[j]);
}
}
ma[left] = ma[i];
ma[i] = temp;
quicksort(ma, left, i - 1);
quicksort(ma, i + 1, right);
}
int a[1000000],b[1000000]={0};
int main() {
struct li ma[100000];
int n, m,k;
cin >> n >> m>>k;
int z=0;
for (int i = 1; i <= n; i++) {
cin>>ma[i].t>>ma[i].x;
z=max(z,ma[i].x);
}
quicksort(ma, 1, n);
queue<int>q;
for(int i=1;i<=n;i++)
{
while(!q.empty()&&ma[q.front()].t+m<=ma[i].t)
{
a[ma[q.front()].x]--;
q.pop();
}
q.push(i);
a[ma[i].x]++;
if(a[ma[i].x]>=k)
{
b[ma[i].x]=1;
}
}
for(int i=0;i<=z;i++)
{
if(b[i]==1)
{
cout<<i<<endl;
}
}
return 0;
}