ACM解题技巧---(尺取法)+ 题目总结

今天学到了尺取这个思路,记下来。

思路 这个技巧其实就是一种。。。。像尺子一样,一段一段的去取,个人觉得这个思想真的挺不错的,思路大概就是通过数组的下标,每次去更新符合实际的左右端点的下标,不断的去更新这个ans答案!!!

第一题

题目传送门
2019年湘潭大学程序设计竞赛(重现赛)F题

题意: 给你一个长度为n的01串,然后m次转换,可以把0字符换成1,也可以把1换成0,最多 转换m次,求最后连续的0,或者连续1最长长度
思路:
第一种思路–>>>> 尺取法,答案要么就是连续的0,要么就是连续的1,所以我们先假设将0换成1,一次去遍历,遇到0,我们就cnt++,直到发现cnt>m(m是操作数),那么我们需要做的就是左边的l进行出队,左边的话,如果遇到是0,那么我们就cnt–,直到cnt<=m,然后我们每次去更新ans

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N = 2e5 + 100, maxn = 5000+10; 
const ll modd = 1e9+7;
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*10+s-'0';s=getchar();}
    x*=f;
}
void solve(){
	int n, m;
	read(n), read(m);
	char s[N];
	scanf("%s",s);
	int l = 0, r = 0, cnt = 0;
	int ans = 0;
	while(r<n){
		if(s[r] == '0')
			cnt++;
		while(cnt>m){
			if(s[l] == '0')
				cnt--;
			l++;
		}
		ans = max(ans,r-l+1);
		r++;
	}
	l = 0, r = 0, cnt = 0;
	while(r<n){
		if(s[r] == '1')
			cnt++;
		while(cnt>m){
			if(s[l] == '1')
				cnt--;
			l++;
		}
		ans = max(ans,r-l+1);
		r++;
	}
	printf("%d\n",ans);
}
int main(){
	int t;
	read(t);
	while(t--){
		solve();
	}
	return 0;
}

第二种思路–>>>> 二分+前缀和

第二题

题目传送门
Hdu1937 Finding Seats

题意: 给你一个矩阵,大小n,m;然后求一个字矩阵,使这个矩阵面积最小,然后空空座位的个数大于等于k,求满足的最小的面积
思路:
最简单思路就是暴力5个循环,其实我们可以这样子去想,我们先枚举这个行,或者去枚举连个列,如果枚举行,(i行到j行),剩下的就是怎么去确定这个列了,题意要求这个面积最小,我们可以去想下,然后转换成一维,剩下的就可以理解成尺子去取,每次去试探,尺子的大小就是k,不断去更新这个一维的端点就行。

AC代码

#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define PI       3.14159265358979323846
using namespace std;
typedef long long int ll; 
typedef unsigned long long int ull;
template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x=f?-x:x;
}

const int maxn = 305;
char mp[maxn][maxn];
int sa[maxn][maxn];

int getsum(int x1, int y1, int x2, int y2){
	return sa[x2][y2] - sa[x2][y1-1] - sa[x1-1][y2] + sa[x1-1][y1-1];
}
int n, m, k;
void solve(){
	
	memset(sa,0,sizeof(sa));
	for(int i = 1; i <= n; i++){
		scanf("%s",mp[i]+1);
		int oo = 0;
		for(int j = 1; j <= m; j++){
			int oo = 0;
			if(mp[i][j]=='.'){
				oo = 1;
			}
			sa[i][j] = oo + sa[i-1][j] + sa[i][j-1] - sa[i-1][j-1]; 
		}
	}
	
	int ans = 0x3f3f3f3f;
	for(int i = 1 ; i <= n; i++){
		for(int j = i ; j <= n; j++){
			int cc = 1;
			for(int kk = 1; kk <= m; kk++){
				
				while(cc<=kk&&getsum(i,cc,j,kk)>=k){
					ans = min(ans,(j-i+1)*(kk-cc+1));
					cc++;
				}
			}
		}
	}	
	printf("%d\n",ans);
	
}
int main(){
	
	
	while(1){
		read(n),read(m),read(k);
		if(n == m && m == k && n == 0){
			break;
		}
		solve();
	}
	return 0;
} 

青春只有一次,让我们撸起袖子,先AC它1000+题

持续更新中…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值