计蒜客 2019 蓝桥杯省赛 B 组模拟赛(题解)

结果填空:马的管辖

题目链接:https://nanti.jisuanke.com/t/A2236

题解:官方给的是二进制枚举,但是我没有看明白^菜^,先贴在这,慢慢体会。

#include <cstdio>
#include <cstring>
using namespace std;

int px[4] = {0, 0, 1, -1};
int py[4] = {1, -1, 0, 0};
int dx[4][2] = {-1, 1, -1, 1, 2, 2, -2, -2};
int dy[4][2] = {2, 2, -2, -2, -1, 1, -1, 1};
int vis[5][5], g[5][5];
int n = 5, m = 5;
bool in(int x, int y) { return x >= 0 && x < n && y >= 0 && y < m; }
int main() {
    int r = n * m;
    int minx = r + r, ans = 0;
    for (int s = 0; s < 1 << r; s++) {
        memset(vis, 0, sizeof(vis));
        int cnt = 0;
        for (int i = 0; i < r; i++) {
            if (s >> i & 1) {
                g[i / m][i % m] = 1;
                cnt++;
            } else {
                g[i / m][i % m] = 0;
            }
        }
        if (cnt > minx) continue;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (g[i][j] == 0) continue;
                vis[i][j] = 1;
                for (int k = 0; k < 4; k++) {
                    int x = i + px[k], y = j + py[k];
                    if (in(x, y) && g[x][y] == 0) {
                        for (int u = 0; u < 2; u++) {
                            int tx = i + dx[k][u];
                            int ty = j + dy[k][u];
                            if (in(tx, ty)) {
                                vis[tx][ty] = 1;
                            }
                        }
                    }
                }
            }
        }
        int ok = 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (vis[i][j] == 0) {
                    ok = 0;
                    break;
                }
            }
        }
        if (ok) {
            if (cnt < minx) {
                minx = cnt;
                ans = 1;
            } else if (cnt == minx) {
                ans++;
            }
        }
    }
    printf("%d %d\n", minx, ans);
    return 0;
}

代码填空:LIS

题目链接:https://nanti.jisuanke.com/t/A2237

题解:LIS有两种方法,这个地方考察的是二分操作,时间复杂度为O(nlogn)。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 9;
int f[N], a[N];
int n;
int find(int l, int r, int x) {
	while (l < r) {
		int mid = (l + r) / 2;
		if (f[mid] < x) {
			l = mid + 1;
		} else {
			r = mid;
		}
	}
	return l;
}
int lis() {
	int len = 0;
	for (int i = 0; i < n; i++) {
		int k = find(0, len, a[i]);
		f[k] = a[i];
		if (k == len) {
			len++;
		}
	}
	return len;
}
int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", a + i);
	}
	printf("%d\n", lis());
	return 0;
}

程序设计:找质数

题目链接:https://nanti.jisuanke.com/t/A2238

题解:水题,欧式筛法和二分查找的基本操作

#include<bits/stdc++.h>
const int MAXN = 1000010;
using namespace std;
 
int is_prime[MAXN];
int primes[MAXN];
int a[MAXN];
int cnt=0;
//欧式筛法
void Euler(){
	is_prime[1]=0;
	for(int i=2;i<MAXN;i++){
		if(is_prime[i])
			primes[cnt++]=i;
		for(int j=0;j<cnt&&i*primes[j]<=MAXN;j++){
			is_prime[i*primes[j]]=0;
			if(i%primes[j]==0)
				break;
		}
	}
}
//二分,也可以用lower_bound
int BinarySearch(int l, int r, int k){
	int mid;
	while(l<r){
		mid=(r-l)/2+l;
		if(primes[mid]<k)
			l=mid+1;
		else
			r=mid;
	}
	return mid;
}
 
int main()
{	
	memset(is_prime,1,sizeof(is_prime));
	memset(primes,0,sizeof(primes));
	Euler();
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>a[i];
	for(int i=0;i<n;i++){
		int r = BinarySearch(0, cnt-1, a[i]);
		int l = 0;
		while(l<=r){
			if(primes[l]+primes[r]==a[i]){
				cout<<primes[l]<<" "<<primes[r]<<"\n";
				break;
			}
			else if(primes[l]+primes[r]>a[i])
				r--;
			else
				l++;
		}
	}
    return 0;
}

程序设计:后缀字符串

题目链接:https://nanti.jisuanke.com/t/A2239

题解:思维题,用到了map,将每个字符串的n到1长度的后缀字符串加入map,并计数,直接用substr截取后缀字符串。

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;

int main() {
    int n;
    cin>>n;
    string st;
    vector<string> s;
    map<string, int> record;
    for(int i=0;i<n;i++){
    	cin>>st;
    	s.push_back(st);
    	for(int j=0;j<st.size();j++)
    		record[st.substr(j)]++;
	}
	for(vector<string>::iterator iter=s.begin();iter!=s.end();iter++)
		cout<<record[*iter]<<"\n";
	
    return 0;
}

程序设计:轻重搭配

题目链接:https://nanti.jisuanke.com/t/A2240

题解:贪心问题,先预处理从小到大排列,然后分成两部分,前一部分依次和后一部分大于等于两倍的匹配,然后注意无法匹配时指针偏移情况就行了。

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
const int MAXN=5*1e5+5;
using namespace std;
int a[MAXN];
int main() {
    int n;
    int res=0;
    cin>>n;
    for(int i=0;i<n;i++)
    	cin>>a[i];
	sort(a,a+n);
	int l=0,r=n/2;
	while(r<n){
		if(a[r]/a[l]>=2){
			res++;
			l++;r++;
		}else{
			res++;
			r++;
		}
	}
	while(l<n/2){
		res++;
		l++;
	}
	cout<<res<<"\n";
}

程序设计:抠图

题目链接:https://nanti.jisuanke.com/t/A2230

题解:这道题DFS和BFS都可以做,首先只保留黑色线框里面的颜色,即存在0环且其内的颜色不变,这道题的用例全是给的0和1,实际上是0到225,是个坑点。为了让0环内的颜色被保护,所以试想不能被0环保护的颜色一定与图的边框相连,所以这道题就可以转化为一个连通分量的问题,我们将图边框上大于0的像素点进入队列,然后将将其置0,然后将依次出队的大于0的像素点进行DFS,将它周围大于0的全部置为0,最后只有0环中的像素点不会受到影响。

#include<bits/stdc++.h>
const int MAXN = 100010;
using namespace std;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int mat[505][505];
int t, n, m;
void dfs(int i, int j){
	for(int d=0;d<4;d++){
		int new_i = i+dx[d];
		int new_j = j+dy[d];
		if(new_i>=0&&new_i<=n-1&&new_j>=0&&new_j<=m-1&&mat[new_i][new_j]>0){
			mat[new_i][new_j]=0;
			dfs(new_i, new_j);
		}
	}
}


int main()
{
	cin>>t;	
	while(t--){
		queue<pair<int, int> > qu;
		cin>>n>>m;
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				cin>>mat[i][j];
				if(i==0||i==n-1||j==0||j==m-1){
					if(mat[i][j]>0){
						qu.push(make_pair(i, j));
						mat[i][j]=0;	
					}
				}
			}		
		}

		while(!qu.empty()){
			dfs(qu.front().first, qu.front().second);
			qu.pop();
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				cout<<mat[i][j];
				if(j==m-1)
					cout<<"\n";
				else
					cout<<" ";
			}
				
		}
			
	}
    return 0;
}

程序设计:蒜厂年会

题目链接:https://nanti.jisuanke.com/t/A2232

题解:这道题和51Nod上的1050 循环数组最大子段和是一样的,不过这道题我是按照官方的做法,用队列来做,破环为链,也就是做将N长度的环转化为2*N的链,然后求前缀和,那么前缀和之差就可以表示那一段的连续之和,这里队列实际上是一个双端队列,维护一个单调队列,让队列元素从小到大,维护一个每次进队的元素和队头元素之差的最大值即可,然后还要判断的是队列中队头元素的索引要小于n-i。

#include<bits/stdc++.h>
#define ll long long 
const int MAXN = 2e5+10;
using namespace std;
int a[MAXN];
ll pre[MAXN];
int main()
{
	deque<int> deq;
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i+n]=a[i];
	}
	pre[0]=0;
	for(int i=1;i<=2*n;i++)
		pre[i]=pre[i-1]+a[i];
	deq.push_back(0);
	ll res=a[1];
	for(int i=1;i<=2*n;i++){
		while(!deq.empty() && deq.front() <i-n)
			deq.pop_front();
		res = max(res, pre[i]-pre[deq.front()]);
		while(!deq.empty() && pre[deq.back()]>=pre[i])
			deq.pop_back();
		deq.push_back(i);
	}
	cout<<res<<"\n";
    return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~Lomiss~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值