学而思4月月赛总结

概况:

T1 T2 T3 T4 T5 T6 T7 T8 sum
60 60 100 4.8 100 50 0 30 404.8

未达到满分题:1,2,4,6,7,8

T1

题目描述

A 和可多喜欢互相切磋井字棋。井子棋就是在九宫格里面轮流放入 12,谁连成 3 个就赢了。虽然小 A 很努力地记录棋谱,可还是下不过可多。由于小 A 比较笨,可多总是让他先。小 A 下的第一个子一定是在中心。这回小 A 希望使用计策。目前棋局刚开始,棋盘上有不大于 3 颗棋子,小 A 想知道,根据目前的局势,他有没有必胜策略(也就是自己以最佳方案下棋,无论对手怎么下,自己必胜)。

输入描述

3行,表示棋局,1 表示小 A2 表示可多,0 表示没有落子。保证棋子数不超过 3 个。

输出描述

2 行。
1 行,如果小 A 赢,输出 "A will win."
如果不知道,输出 "Dont know."
2 行,输出棋局刚开始时他们已经下了几个棋子。

样例1
输入
0 0 0
0 1 0
0 0 0
输出
Dont know.
1
样例2
输入
0 0 0
0 1 0
0 2 1
输出
A will win.
3
考场代码 (60p)
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a[4][4]={},cnt=0;
	for(int i=1;i<=3;i++)
		for(int j=1;j<=3;j++)
			cin>>a[i][j];
	for(int i=1;i<=3;i++)
		for(int j=1;j<=3;j++)
			if(a[i][j]!=0) 
				cnt++;
	if(cnt==1||cnt==2) puts("Dont know.");
	else if((a[1][1]==1&&a[3][3]==0)||(a[1][3]==1&&a[3][1]==0)||(a[1][1]==0&&a[3][3]==1)||(a[1][3]==0&&a[3][1]==1)) 
		puts("A will win.");
	else if((a[1][2]==1&&a[3][2]==0)||(a[2][1]==1&&a[2][3]==0)||(a[1][2]==0&&a[3][2]==1)||(a[2][1]==0&&a[2][3]==1)) 
		puts("A will win.");
	else if((a[1][1]==1&&a[3][3]==1)||(a[1][3]==1&&a[3][1]==1)||(a[1][2]==1&&a[3][2]==1)||(a[2][1]==1&&a[2][3]==1)) 
		puts("A will win.");
	else puts("Dont know.");
	cout<<cnt;
	return 0;
}

正解思路:

由题目中可知,我们能够获取到 5 个直接条件,1 个推导条件:

  1. 在九宫格里面轮流放入 12,连成 3 个就赢了
  2. A
  3. A 的第一个子一定是在中心
  4. 1 表示小 A2 表示可多,0 表示没有落子
  5. 保证棋子数不超过 3
  6. 可多最多只有 1 个棋子

我们可以考虑使用 if语句判断来解决这个问题,直接且时间复杂度低。所以将所有的 Dont know 通过 if语句 排除,剩下的就是 A will win.

Dont know 情况:

  • 只有 1 个子
  • 可多下在角落
  • 有一列或一行全都落子
正解代码:
#include<bits/stdc++.h>
using namespace std;
int main(){ 
    int a[5][5],cnt=0;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
            cin>>a[i][j];
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
          if(a[i][j]!=0)
              cnt++;
    if(cnt==1){
        puts("Dont know.");
        cout<<1;
        return 0;
    } 
    if(a[1][1]==2||a[1][3]==2||a[3][1]==2||a[3][3]==2){
        puts("Dont know.");
        cout<<cnt;
        return 0;
    } 
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
            a[i][4]=a[i][1]+a[i][2]+a[i][3];
            a[4][j]=a[1][j]+a[2][j]+a[3][j];
        }
    if(cnt==3){
        for(int i=1;i<=3;i++){
            if(a[i][4]==4||a[4][i]==4){
                puts("Dont know.");
                cout<<3;
                return 0; 
            }
        }
    } 
    puts("A will win.");
    cout<<cnt;
    return 0;
}

T2

题目描述

学校规定,进校门必须佩戴红领巾。
某一天,可多和同学们共 n 人出门玩耍。但在回学校时,他们发现只有 m 个人戴了红领巾。
他们决定,先让 m 个人戴红领巾进入学校,再派一个人带着所有 m 条红领巾出来。重复这个过程,直到所有人都回到学校。
假设进出学校都需要花费 1 个单位的时间,但可以很多人同时进出。
求让所有人都回到学校最少需要花费多少单位时间。

输入描述

输入由多组数据构成。
第一行一个正整数 T,表示共有 T 组数据。
对于每组数据,有一行两个正整数 nm,用一个空格隔开,分别表示人数及红领巾的数量。

输出描述

对于每组数据,输出一行一个整数表示答案。
特别地,如果无法让所有人都回到学校,输出 -1

样例
输入
3
6 3
10 10
10 1
输出
5
1
-1
考场代码 (60p)
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		if(m==1)
		{
			puts("-1");
			continue;
		}
		if(n==m)
		{
			puts("1");
			continue;
		}
		if((n-1)%(m-1)==0) cout<<n/(m-1)*2-1<<endl;
		else if(n%(m-1)==0) cout<<n/(m-1)*2-1<<endl;
		else cout<<n/(m-1)*2+1<<endl;
	}
	return 0;
}

正解思路:

什么时候会输出 -1?只要 1 轮可以进去至少 1 个人,就是可行的。但是当红领巾只有 1 条且人数大于 1 时,就是不可能的情况,输出 -1
接下来要考虑一般情况。可以想到,每一次进去 m 人,出来 1 人,耗费 2 单位的时间。最后肯定还会剩下一些人,1 单位的时间就可以都进去。最后输出时间即可。

正解代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n,m;
		cin>>n>>m;
		if(m==1&&n!=1) puts("-1");
		else
        {
			int t=0;
			while(n-m>0)
			{
				n-=(m-1);
				t+=2;
			}
			t+=1;
			cout<<t<<endl;
		}
	} 
	return 0;
}

T4

题目描述

N 颗糖果摆成一排,第 i 颗糖果的颜色为 ci,在这一排糖果中,你可以选择其中连续的 K 个糖果并且获得他们。
你喜欢吃五彩缤纷的糖果,所以你获得的糖果不同颜色越多,就越高兴。
输出你能获得的最多的糖果颜色数

输入描述

第一行两个数字 NK
第二行 N 个数字,表示每个糖果的颜色 ci

输出描述

一行一个整数,表示你能获得的最多糖果颜色数。

样例1
输入
7 3
1 2 1 2 3 3 1
输出
3
样例2
输入
10 6
1 3 1 3 4 1 2 1 1 2 
输出
4
考场代码 (4.8p)
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,k,c[3005],f[3005]={};
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>c[i];
	multiset<int> ms;
	set<int> s;
	for(int i=1;i<=k;i++) 
	{
		s.insert(c[i]);
		ms.insert(c[i]);
	}
	f[k]=s.size();
	for(int i=k+1;i<=n;i++)
	{
		if(ms.count(c[i-k])==1) s.erase(c[i-k]);
		ms.erase(ms.find(c[i-k]));
		s.insert(c[i]);
		ms.insert(c[i]);
		f[i]=s.size();
	}
	int maxn=0;
	for(int i=1;i<=n;i++) maxn=max(maxn,f[i]);
	cout<<maxn;
	return 0;
}

正解思路:

先计算前 k 个糖果有多少不同的颜色,再利用滑动窗口思想,每次将新一位加入,用桶判断是否已经存在该颜色,最后求出最大值输出。

正解代码:
#include<bits/stdc++.h>
using namespace std;
int c[300005],sm[300005];
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>c[i];
    int cur=0,head=1;
    for(int i=1;i<=k;i++)
    {
        sm[c[i]]++;  
        if(sm[c[i]]==1) cur++;
    }
    int ans=cur;
    for(int i=k+1;i<=n;i++)
    {
        sm[c[i]]++;
        if(sm[c[i]]==1) cur++;
        sm[c[head]]--;
        if(sm[c[head]]==0) cur--;
        head++;
        ans=max(ans,cur);
    }
    cout<<ans;
    return 0;
}

T6

题目描述

卡普有 n 个整数,他想消灭掉其中的所有负数。他会进行若干次操作,每次选择两个数字,并将它们同时变成它们的乘积。
由于卡普非常聪明,只要这不是不可能的,他就能用最少次数的操作做到这一点。
请你找出他最少操作几次能消灭掉所有负数,或者告诉他这不可能。

输入描述

第一行一个正整数 n
第二行 n 个整数 a1n,用一个空格隔开,表示初始时的数字。

输出描述

输出一行一个整数表示答案。
如果无解,则输出 -1

样例1
输入
5
1 -1 7 2 3
输出
2
样例2
输入
4
3 -1 0 4
输出
1
样例3
输入
1
-7
输出
-1
考场代码 (50p)
#include<bits/stdc++.h>
using namespace std;
int main()
{
	bool f0=0;
	long long n,c[3005],fs=0;
	cin>>n;
	for(long long i=1;i<=n;i++) 
	{
		cin>>c[i];
		if(c[i]<0) fs++;
		if(c[i]==0) f0=1;
	}
	if(fs%2==0) cout<<fs/2;
	else if(f0) cout<<fs/2+1;
	else if(fs!=n) cout<<fs*2;
	else cout<<-1;
	return 0;
}

正解思路:

在输入的同时记录是否有 0 以及负数的个数。
消灭负数的方法 (设负数个数为 w):

  • 两两相乘 (负数个数为 2 的倍数时),w2
  • 0 乘负数 (有 0 时),w12+1
  • 负数乘整数,再将两个负数相乘 (有正数时),w+12+1

分类讨论输出即可。

正解代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
	bool f0=0;
	long long n,c[3000005],fs=0;
	cin>>n;
	for(long long i=1;i<=n;i++) 
	{
		cin>>c[i];
		if(c[i]<0) fs++;
		if(c[i]==0) f0=1;
	}
	if(fs%2==0) cout<<fs/2;
	else if(fs%2==1&&f0) cout<<(fs-1)/2+1;
	else if(fs%2==1&&fs!=n) cout<<(fs+1)/2+1;
	else cout<<-1;
	return 0;
}

T7

题目描述

给定 n 个点和 m 个关系,每个关系的格式如下:
给出编号 x,y 和数字 a,b。假设 x 的坐标是 (u,v),那么y的坐标是 (u+a,v+b)
已知1号点的坐标是 (0,0),请你根据这 m 条关系确定这 n 个点的坐标。
如果某个点的坐标无法确定,输出 undecidable

输入描述

第一行两个整数 n,m
接下来 m 行,每行 4 个整数表示 x,y,a,b

输出描述

n 行,每行两个整数,第 i 行的 2 个整数表示第 i 个点的坐标。

样例1
输入
3 2
1 2 2 1
1 3 -1 -2
输出
0 0
2 1
-1 -2
样例2
输入
3 2
2 1 -2 -1
2 3 -3 -3
输出
0 0
2 1
-1 -2
样例3
输入
5 7
1 2 0 0
1 2 0 0
2 3 0 0
3 1 0 0
2 1 0 0
3 2 0 0
4 5 0 0
输出
0 0
0 0
0 0
undecidable
undecidable
正解思路:
正解代码:

T8

题目描述

兰朵在玩自己设计的新游戏,她目前陷入了一场苦战。
战斗的场地由 n 行,m 列的地板组成。每块地板上可能是关卡,也可能是城堡的承重柱。
地板上的数字会描述地板状态。如果地板上是一个正整数,就表示这道关卡的怪物数量,如果为 0,表示这块地板是城堡的承重柱。
兰朵可以选择任意一块没有承重柱的地板,然后进行十字切割。

十字切割的效果如下:

  • 被选中的地板会拥有十字切割的覆盖范围。
  • 从被选中的那块地板开始从上下左右 4 个方向直线延伸覆盖范围,直到遇到承重柱或者到达战斗场地边界停止。
  • 十字切割覆盖范围内的所有怪物都会被击败。

兰朵的体力只允许她使用 1 次十字切割,她想知道自己最多能击败多少只怪物。

输入描述

第一行两个正整数 nm,用一个空格分隔,表示战斗场地的大小。
接下来 n 行,每行输入 m 个非负整数 aij,用一个空格分隔,表示第 i 行,第 j 列地板上的数字。

输出描述

输出一行一个整数表示答案。

样例1
输入
3 3
1 1 1
1 0 1
0 1 1
输出
5
样例2
输入
5 5
1 9 1 1 9
1 0 1 0 1
0 9 9 9 0
0 1 0 1 1
1 1 1 0 1
输出
31
考场代码 (30p)
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 50;
int n, m;
vector<vector<int> > field;
vector<vector<bool> > visited;
int max_kills = 0;
void dfs(int x, int y, int& kills) {
    if (x < 0 || x >= n || y < 0 || y >= m || field[x][y] == 0 || visited[x][y]) {
        return;
    }
    visited[x][y] = true;
    kills += field[x][y];
    dfs(x + 1, y, kills);
    dfs(x - 1, y, kills);
    dfs(x, y + 1, kills);
    dfs(x, y - 1, kills);
}
int main() {
    cin >> n >> m;
    field.resize(n, vector<int>(m));
    visited.resize(n, vector<bool>(m, false));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cin >> field[i][j];
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (field[i][j] != 0) {
                int kills = 0;
                dfs(i, j, kills);
                max_kills = max(max_kills, kills);
            }
        }
    }
    cout << max_kills << endl;
    return 0;
}
正解思路:
正解代码:

posted @   XLoffy  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示