窗口滑动
Note:这里的窗口滑动并非指的是滑动窗口(即单调队列)问题,而是处理问题的技巧。
题目:来自ABC337的D - Cheating Gomoku Narabe
链接: ABC337
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int h, w, k;
cin >> h >> w >> k;
vector<string> s(h);
for(int i = 0;i < h;i ++){
cin >> s[i];
}
int x, o;
int ans = k + 1;
for(int i = 0;i < h;i ++){//每行开始枚举
x = 0, o = 0;
for(int j = 0;j < w;j ++){
if(s[i][j] == 'o'){
o ++;
}
if(s[i][j] == 'x'){
x ++;
}
if(j >= k - 1 && !x){//中间不能有阻碍
ans = min(ans, k - o);
}
if(j >= k - 1){
if(s[i][j - k + 1] == 'o'){//窗口开始滑动
o --;
}
if(s[i][j - k + 1] == 'x'){
x --;
}
}
}
}
for(int j = 0;j < w;j ++){
x = 0, o = 0;
for(int i = 0;i < h;i ++){
if(s[i][j] == 'o'){
o ++;
}
if(s[i][j] == 'x'){
x ++;
}
if(i >= k - 1 && !x){//中间不能有阻碍
ans = min(ans, k - o);
}
if(i >= k - 1){
if(s[i - k + 1][j] == 'o'){//窗口开始滑动
o --;
}
if(s[i - k + 1][j] == 'x'){
x --;
}
}
}
}
cout << (ans > k ? -1 : ans);
return 0;
}
重量相同小球找不同最小次数问题
技巧:重量相同的一堆小球中找不同问题,n - 1有几个二进制位就代表至少要几个人,如 n = 10, 则 0 ~ 9 为0000 ~ 1111,说明至少需要4个人,n = 8, 则 0 ~ 7为000 ~ 111,则至少需要3个人。
题目:来自ABC337的E - Bad Juice
链接: ABC337
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
int m = 0,p = n - 1;
while(p){
m ++;
p = p >> 1;//(重量相同的一堆小球中找不同问题,n - 1有几个二进制位就代表至少要几个人,如 n = 10, 则 0 ~ 9 为0000 ~ 1111,说明至少需要4个人,n = 8, 则 0 ~ 7为000 ~ 111,则至少需要三个人)
}
cout << m << endl;
//其中第一个人分到的是二进制最后一位为1的juice,第二个人分到的是二进制倒数第二位为1的juice....以此类推·
vector<vector<int>> a(m + 1);
for(int i = 1;i <= m;i ++){
for(int j = 0;j < n;j ++){
if(j >> (i - 1) & 1){
a[i].push_back(j);
}// 用来判断这个数二进制的第几位是什么(是否1)
}
}
for(int i = 1;i <= m;i ++){
cout << a[i].size() << " ";
for(auto x : a[i]) cout << x << " ";
cout << endl;
}
string s;
cin >> s;
reverse(s.begin(), s.end());
int sum = 0;
for(int i = 0;i < (int)s.size();i ++){
sum += (s[i] - '0') * pow(2 , s.size() - 1 - i);//二进制转化成是十进制
}
cout << (sum == 0 ? n : sum) << endl;
return 0;
}
二维数组和一维数组相互转化问题
解法:假如一维数组的下标是 k, 要转化成n行n列的二维数数组,则x = k / n, y = k % n;
x ,y 的二维数组转化成一维数组,则k = x * n + y;
题目 : 来自acwing- bfs的八数码问题
链接: 八数码
AC代码:
#include<bits/stdc++.h>
using namespace std;
int bfs(string start){
string end = "12345678x";
queue<string> q;
unordered_map<string, int> d;
q.push(start);
d[start] = 0;
int dx[4] = { 0, -1, 0, 1}, dy[4] = { 1, 0, -1, 0};
while(!q.empty()){
auto t = q.front();
q.pop();
int distance = d[t];
if(t == end) return distance;
int k = t.find('x');//找到x的下标
int x = k / 3,y = k % 3;//一维数组转化为二维数组
for(int i = 0;i < 4;i ++){
int a = x + dx[i],b = y + dy[i];
if(a >= 0 && a < 3 && b >= 0 && b < 3){
swap(t[k], t[a * 3 + b]);//将二维数组转化为一位数组
if(!d.count(t)){
d[t] = distance + 1;
q.push(t);
}
swap(t[k],t[a * 3 + b]);
}
}
}
return -1;
}
int main(){
string start;
for(int i = 0;i < 9;i ++){
char c;
cin >> c;
start += c;
}
cout << bfs(start);
return 0;
}
贪心!区间选点
区间选点问题就是指在几个区间里选出最少的点使得每个区间里面都有点。
题目:(模板题)
模板代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct node{
int l, r;
}a[N];
bool cmp(node b, node c){
return b.r < c.r;
}
int main(){
int n;
cin >> n;
for(int i = 0;i < n;i ++){
cin >> a[i].l >> a[i].r;
}
sort(a, a + n, cmp);
int cnt = 1;
int right = a[0].r;
for(int i = 1;i < n;i ++){
if(a[i].l > right){
right = a[i].r;
cnt ++;
}
}
cout << cnt;
return 0;
}
题目:雷达设备
本题是一个二维的,但本题最关键的点就是把二维问题转化成一维问题
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
struct node{
double l, r;
}a[N];
bool cmp(node b, node c){
return b.r < c.r;
}
int main(){
int n, d;
cin >> n >> d;
for(int i = 0;i < n;i ++){
double x, y;
cin >> x >> y;
if(y > d){
cout << -1 << endl;
return 0;
}else{
double len = sqrt(d * d - y * y);
a[i].l = x - len;
a[i].r = x + len;
}
}
sort(a, a + n, cmp);
int cnt = 1;
double right = a[0].r;
for(int i = 1;i < n;i ++){
if(a[i].l > right){
right = a[i].r;
cnt ++;
}
}
cout << cnt;
return 0;
}