1.双指针
1.1日志统计
暴力
双指针
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 100010;
int n,d,k;
PII logs[N]; //记录
int cnt[N]; //所有id出现的次数
bool st[N]; //判断每一个帖子是否在热帖
int main()
{
scanf("%d%d%d",&n,&d,&k);
for(int i = 0;i < n;i++) scanf("%d%d",&logs[i].x,&logs[i].y);
sort(logs,logs + n);
for(int i = 0,j = 0;i < n;i++)
{
int id = logs[i].y;
cnt[id]++;
while(logs[i].x - logs[j].x >= d)
{
cnt[logs[j].y]--;
j++;
}
if(cnt[id] >= k) st[id] = true;
}
for(int i = 0;i < N;i++)
if(st[i]) printf("%d\n",i);
return 0;
}
2.BFS
2.1献给阿尔吉侬的花束
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#define x first
#define y second
using namespace std;
const int N = 210;
typedef pair<int, int> PII;
int n, m;
char g[N][N];
int dist[N][N]; // 把判重和距离数组合为一个
int bfs(PII start, PII end) // 注意 start end都是PII类型的 别写错了
{
queue<PII> q;
memset(dist, -1, sizeof dist); // 把距离数组都初始化成-1
dist[start.x][start.y] = 0; // 起点开始,距离为0
q.push(start); // 起点 入队
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
while(q.size())
{
PII t = q.front();
// 弹出队头
q.pop();
for (int i = 0; i < 4; i ++ )
{
int a = t.x + dx[i], b = t.y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= m) continue; // 出界,跳出本次循环
if (dist[a][b] != -1) continue; // 走过了,跳出本次循环
if (g[a][b] == '#') continue; // 撞到障碍物
dist[a][b] = dist[t.x][t.y] + 1;
if (end == make_pair(a, b)) return dist[a][b]; // 走到终点了,返回距离
q.push({a, b});
}
}
return -1;
}
int main()
{
int T;
cin >> T;
while(T --)
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
PII start, end;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == 'S') start = {i, j};
else if (g[i][j] == 'E') end = {i, j};
int distance = bfs(start, end);
if (distance == -1) printf("oop!\n");
else printf("%d\n", distance);
}
return 0;
}
注:make_pair(x,y)
可以返回一个pair
make_pair(x,y)
3.图论
3.1交换瓶子
暴力
1、通过观察可以发现,我们每一个数都必须回到它自己的位置上,比如 1 必须在第一位,2 必须在第二位上
2、那么我们就可以这样操作,由于每个数必须回到自己的位置,直接从 1 枚举到 n,如果当前位置的数不等于它的下标,那么我们就必须要把它给替换掉
3、设当前位置为 i 的话,那么我们就从 i+1 开始往后枚举,直到找到对应的 a[j] 和我们的 i 相等,那么我们就把上个数交换,把交换次数++
4、容易证明这个算法的正确性,由于每个数必须回到原来的位置,所以我们这样子操作不会出现多于的步骤,因为每次操作都是必须的,即使这个算法看起来很麻烦
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int a[N],n,t;
int ans=0;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
if(a[i]!=i)
{
for(int j=i+1;j<=n;j++)
{
if(a[j]==i)
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
ans++;
}
}
cout<<ans<<endl;
return 0;
}
置换群算法
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int n;
int b[N];
bool st[N];//判重数组
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);
int cnt = 0;
//找环,统计环的数量
for (int i = 1; i <= n; i ++ )
if (!st[i])//当前这个点未被找到
{
cnt ++ ;
for (int j = i; !st[j]; j = b[j])//这个点可以到的所有点
st[j] = true;
}
printf("%d\n", n - cnt);
return 0;
}