ZAFU寒假个人赛2022.01.22题解

A - AtCoder - abc234_a

题目大意

给出函数 f(x)=x2+2x+3 , g(t)=f(f(f(t)+t)+f(f(t))) ,输入 t, 计算结果 g(t) 并输出.

分析

本场比赛的签到题之一,旨在考察同学们递归的使用和基本的语法知识。题给数据保证不超过 1e9,没有坑点,计算输出即可

一血同学代码

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
const ll INFF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
#define dbg(x) cout << #x << "=" << x << endl;

ll f(ll x){
    return x*x+2*x+3;
}
ll n;
void solve(){ 
    cin >> n;
    cout << f(f(f(n)+n) + f(f(n)));
}
int main()
{
    //IOS //int t;cin >> t;
    //while (t--)
        solve();
    return 0;
}

B - AtCoder - abc221_b

题目大意

题给两字符串 ST,长度均不超过 100。

判断 S 是否能交换相邻两个字符 或者不进行操作,使 S 等价于 T

分析

本场比赛的签到题之一,旨在考察同学们基本的字符串模拟能力. 下面提供两种简单的做法。

  1. 暴力枚举所有可能的交换情况。O(n2)
  2. 逐字符判断两个字符串的异同。如有不同,则和后续字符交换,然后判断两个字符串是否相同。O(n)

一血同学代码O(n2)

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
const ll INFF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
#define dbg(x) cout << #x << "=" << x << endl;

ll f(ll x){
    return x*x+2*x+3;
}
ll n;
void solve(){ 
    string a, b;
    cin >> a >> b;
    if (a == b){
        cout << "Yes" << endl;
        return ;
    }
    for (int i=0; i<a.size()-1; i++){
        swap(a[i],a[i+1]);
        if (a == b){
            cout << "Yes" << endl;
            return ;
        }
        swap(a[i],a[i+1]);
    }
    cout << "No" << endl;
}
int main()
{
    //IOS //int t;cin >> t;
    //while (t--)
        solve();
    return 0;
}

官方题解代码O(n)

#include<bits/stdc++.h>
using namespace std;

int main(){
    string S,T; cin >> S >> T;
    string ans = "No";
    if(S == T) ans = "Yes";
    for(int i=0; i<S.size(); i++){
        if(S[i] != T[i]){
            if(0 < i){
                swap(S[i-1],S[i]);
                if(S == T) ans = "Yes";
                swap(S[i-1],S[i]);
            }
            if(i+1 < S.size()){
                swap(S[i],S[i+1]);
                if(S == T) ans = "Yes";
                swap(S[i],S[i+1]);
            }
            break;
        }
    }
    cout << ans << endl;
}


C - CodeForces - 339A

本题翻译存在歧义,向同学们致歉

题目大意

给出一个只存在 ’+‘,和数字 1,2,3的运算表达式,要求输出每项按照非递减顺序排列的表达式。

分析

本场比赛的签到题之一,旨在考察同学们排序,模拟等基本操作。按照题意模拟输出即可。

一血同学代码

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define int long long 
#define re register int
#define pb emplace_back
#define lowbit(x) (x&-x)
#define fer(i,a,b) for(re i = a ; i <= b ; i ++)
#define der(i,a,b) for(re i = a ; i >= b ; i --)
#define snow ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
typedef pair<int,int>PII;
typedef pair<int,string>PIS;
signed main(){
    string s;
    cin>>s;
    vector<int>S;
    for(int i=0;i<s.size();i++){
        if(s[i]!='+')S.push_back(s[i]-'0');
    }
    sort(S.begin(),S.end());
    bool st=false;
    for(auto x:S){
        if(!st)cout<<x,st=true;
        else cout<<'+'<<x;
    }
    cout<<endl;
    return 0;
}
#简单易懂的python代码
s = input().split('+')
s.sort(reverse=False)
print ('+'.join(s))

D - CodeForces - 1494B

题目大意

给你一个全白的网格,然后要你把最上面一行,最下面一行,最左边一列和最右边一列涂上给定数量的黑色,问的涂法。

分析

本场比赛的签到题之一(我认为,但是过的人有点少),大二的同学应该都有写过,是之前校赛题目的简单版本。

很容易可以看出来,处理四个角是本题的关键。角上的点会影响两条边,我们只需要暴力枚举每个点涂与不涂然后进行check即可。这里可以用四个for循环分别枚举,或是用位运算表示。举个例子, 用 ”0010“,表示只涂左下角的方格, 用”1111“ 表示四个角都涂。详情同学们可以学习位运算深入了解。(可以尝试搜索Matrix67 位运算)个人觉得用位运算进行暴力枚举是非常需要掌握的,同时会为你以后学状压dp打下良好的基础。

本题还可以采用分类讨论的方式ac,但是如果题目条件扩展到三维,会变得极其繁琐,此处不作详细介绍。我第一次就是这么过的,校赛被制裁了

一血同学代码

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
const ll INFF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
#define dbg(x) cout << #x << "=" << x << endl;

int n,u,r,d,l;
void solve(){ 
    cin >> n >> u >> r >> d >> l;
    int uu=u,rr=r,dd=d,l1=l;
    for (int i=0; i<2; i++)
        for (int j=0; j<2; j++)
            for (int h=0; h<2; h++)
                for (int k=0; k<2; k++)
                {
                    u=uu;r=rr;d=dd;l=l1;
                    if (k){
                        u--;
                        l--;
                    }
                    if (h){
                        u--;
                        r--;
                    }
                    if (j){
                        d--;
                        l--;
                    }
                    if (i){
                        d--;
                        r--;
                    }
                    if (u<0||d<0||l<0||r<0){
                         continue;
                    }
                    if (u < n-1 && r<n-1 && l<n-1 && d<n-1){
                        cout << "YES" << endl;
                         return ;
                    }
                }

    
     cout << "NO" << endl;
}
int main()
{
    IOS int t;cin >> t;
    while (t--)
        solve();
    return 0;
}

E - AtCoder - abc221_c

题目大意

给定一个数字 n ,将这个数字中的数任意排列组合分成两份,问你如何组合成两个数,使得这两个数的乘积最大。

分析

本题本质是一个全排列问题,数据范围不大因此,枚举全排列然后维护一个最大值即可。同时介绍一下,next_permutation,的用法。全排列也可以通过 dfs ,或者数学方法生成,此处不详细介绍,同学们有兴趣的可以自己查找相关资料。

贪心也可以通过本题,一道贪心,显然越大的数尽可能在前面对双方相乘整体的贡献越大。从9 ~ 0 的数从高位平分给两边。要注意优先分配给较小的数。如 4 3 2, 依次分配时, 2 应该分配给 3,而不是 4, 32 * 4 > 42 * 3。

水平有限难以进行严格的证明(暴力能过的题目又有谁会去想其他做法呢)

一血同学代码

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
const ll INFF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
#define dbg(x) cout << #x << "=" << x << endl;

int n,u,r,d,l;
void solve(){ 
    string s, t;
    cin >> s;
    sort(s.begin(),s.end());
    t = s;
    int ans = 0;
    while (1){
        //cout << s<< endl;
        for (int i=1; i<s.size(); i++)
        {
            int a = stoi(s.substr(0,i));
            int b = stoi(s.substr(i,s.size()-i));
            //cout << a << ' ' << b << endl;
            ans = max(ans, a*b);
        }
        next_permutation(s.begin(), s.end());
        if (s == t) break;
    }
    cout << ans << endl;
}
int main()
{
    IOS //int t;cin >> t;
    //while (t--)
        solve();
    return 0;
}

贪心同学代码(%%%)

#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
int a[100];
int b[100];
int d[100];
int e[100];
int idx1, idx2;
int c[100], idx3;
int idx4, idx5;
int main() {
	IOS;
	int n; cin >> n;
	while (n) {
		c[++idx3] = n % 10;
		n /= 10;
	}
	sort(c + 1, c + 1 + idx3);

	ll n1 = 0, n2 = 0;
	for (int i = idx3; i >= 1; i--) {
		if (n1 <= n2) {
			n1 += c[i];
			n1 *= 10;
		}
		else {
			n2 += c[i];
			n2 *= 10;
		}
	}
	n1 /= 10; n2 /= 10;
	cout << n1 * n2 << endl;
}


F - AtCoder - abc210_c

题目大意

n 颗糖果排成一列,每颗糖果有一种颜色。选一段长度为 k 的区间,取尽可能多的颜色的糖果。

分析

普普通通的滑动窗口,或者叫双指针。(什么你还不会?从acwing 算法基础课第一节开始学吧!)简单来说把一段区间不断向前推进,每次减去最前面的糖果,加上后面的糖果。维护颜色数量最多即可。大部分不会做的同学是死在了不会使用 map 上,糖果颜色超过 1e9 种,数组记不下来了。(这个问题刚开始学我也遇到过,手足无措)建议未过的同学学习一下 map 的用法。

一血同学代码

#include <iostream>
#include <cstring>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <ctime>
#include <bitset>
#include <cassert>
#include <iomanip>
//#define int long long
#define endl '\n'
using namespace std;
const int N = 300010, M = 2 * N, INF = 0x3f3f3f3f;
const int mod = 998244353;
typedef pair<int, int> PII;
int T, n, m, c1, c2;
int a[N], b[N], ans, k;
unordered_map<int, int> mp;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int res = 0;
    cin >> n >> k;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= k; i++)
    {
        if (!mp[a[i]]) ans++;
        mp[a[i]]++;
    }
    res = ans;
    for (int i = k + 1, j = 2; i <= n; i++, j++)
    {
        if (!mp[a[i]]) ans++;
        mp[a[i]]++;
        mp[a[j - 1]]--;
        if (!mp[a[j - 1]]) ans--;
        res = max(res, ans);
    }
    cout << res << endl;
    
    return 0;
}

H - AtCoder - abc215_d


为什么没有 G ? 因为 F 后面就是 H 呀 !(bushi), 本题解主要面向新生,赛中过题人数少于10的不收录。(希望ycy不要看到)

题目大意

给出你 n 个数,让你在 [1,m] 范围那找出与这 n 个数都互质的数。

分析

本题涉及一点质数筛的知识,还是推荐下 acwing 的算法课 qvq 你要是会质数筛还没做出来这题。emmmmm,不太可能吧。

首先我们正向的想。 下面 ai 表示题给出的 n 个数的第 i 个数,用 Ai 表示 [1,m] 中与 ai 互质的数的集合。那么题目答案即可表示为

A1A2A3A4...An

即为对所有数的答案集合取一个交集。有同学是这么做的,这样做的复杂度太高然后 TLE 了。上述表达式等价于

U(A1¯A2¯A3¯A4¯...An¯)

并集比交集好求得多。对于 A¯i , 我们只需要将其分解质因数,然后用质因子筛一遍区间即可。并集比交集好求得多。

最后答案就是,把所有数的质因子标记出来,然后用质因子筛一遍原区间即可得到答案。

一血同学代码

#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<vector>
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define x first 
#define y second
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
int n,m;
bool a[100010];
int main(){
	IOS
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		for(int j=2;j<=x/j;j++){
			if(x%j==0){
				a[j]=1;
				while(x%j==0)x/=j;
			}
		}
		if(x>1)a[x]=1;
	}
	vector<int> ans;
	for(int i=1;i<=m;i++){
		int x=i;
		bool is=1;
		for(int j=2;j<=x/j;j++){
			if(x%j==0){
				if(a[j]){
					is=0;
					break;
				}
				while(x%j==0)x/=j;
			}
		}
		if(a[x])is=0;
		if(is)
		ans.pb(i);
	}
	cout<<ans.size()<<endl;
	for(int &i:ans)cout<<i<<endl;
	return 0;
}
posted @   sweet_guagua  阅读(171)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示