Loading

Loading

2025深大电协软件部招新个人题解(部分)

2025深大电协软件部招新个人题解(部分)

Miya555忙里偷闲凑出三个小时参与了此次比赛(?),后面题絮絮叨叨的没时间看了,练练手。

前言:ACM赛制,我的完成度(9/15),题目大部分要么小清新,要么套路,洛谷难度来看红到紫都有,基本以橙黄题为主。最后一题出现了主席树,可爱捏,被我一眼丁真然后跳过了(完全不会)。

不过这份题目放在大一来招新有点超标了吧,我感觉对初学者太不友好了。虽然我不是初学者。

image

image

题解部分

A0无畏契约的ACS之谜

签到题,a+b problem四舍五入版

#include<bits/stdc++.h>
using namespace std;
long long n,a,b,c;
long long tmp,tot;
int main()
{
	cin>>n;
	for(long long i=1;i<=n;i++)
	{
		cin>>a>>b>>c;
		tot+=a*150+b*25+c*50;
		if(a>1)
		{
			tot+=30*(a-1);
		}
		
	}
//	tmp=0;
	cout<<tot/n;	
	return 0;
}

A1尾巴的自我复制

这道题是一个小清新字符串,使用string的小巧思很快解决。

我一开始想成了回文串,手推了一下发现不对,可以直接用substr暴力拆开,两层for循环搞定,一开始还以为会超时,这个数据放的也太松了。

如果我是万恶的出题人,我将严卡TLE

image

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

int main() {
    string s;
    cin >> s;
    int n = s.length();
    for (int len = 1; len <= n; len++) {
        bool valid = true;
        for (int i = len; i < n; i += len) {
            string cur = s.substr(i, len);
            string tmp = s.substr(0, len); 
            if (cur != tmp) {      
                string re = tmp;
                reverse(re.begin(), re.end());
                if (cur != re) {
                    valid = false;
                    break;
                }
            }
        }

        if (valid) {
            cout << len << endl;
            return 0;
        }
    }
   
  //  cout << n << endl;
    return 0;
}

A2 圣遗物词条

image

一开始读题感觉很数学,所以直接开始推式子,兜兜转转通过加加减减发现了神秘的状态转移:

f[i][j] 为把 i 拆分为 j 个数的方案数,则

\[f[i][j]=f[i-1][j-1]+f[i-j][j] \]

这是一个十分重要的表达式,有些难以理解,我画了一下:

67a3996549a2f794c594ce9d5267cb63

确实很有意思,推完之后茅塞顿开,高中的时候教练好像讲过?

后面的代码就很简单了

#include<bits/stdc++.h>
using namespace std;
int f[1010][1010];
//我服了吧,居然是dp,我怎么这么蠢了?
int main() {
    int n, m;
    cin >> n >> m;

    // 初始条件:0拆分为0个数,1种方式
    f[0][0] = 1; 
    
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (i >= j) {
                f[i][j] = f[i - 1][j - 1] + f[i - j][j];
            }
        }
    }
    
    cout << f[n][m] << endl;
    return 0;
}

A3 爬楼梯的修行

就是你知道的那个爬楼梯的小变式题。。难度上不到普及-

变处在于 “一步可以跨M级台阶”

在for循环中再做m次加法就可以了

image

#include<bits/stdc++.h>
using namespace std;
int n,m,f[100010],tmp=1;
const int N=114514;
int main()
{
//	f[1]=1,f[2]=2;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		f[i]=tmp;
		tmp+=f[i];
		tmp%=114514;
	}
	for(int i=m+1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			f[i]+=f[i-j];
			f[i]%=114514;
		}
	//	f[i]=f[i-1]+f[i-2];
	}
	cout<<f[n];
	return 0;
}

不过我当时傻了还弄了个预处理,第一个for循环可以直接使用第二个来代替。代码更少。

A4 门扉前的弈局

image

刚刚看到这道题以为是过河卒,后面发现又没那么相似。

思路是BFS,一步一步扩展。

先使用两个数组来存储上下前后的位置,用队列来维护坐标

这道题要比较细心!

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int n, m, x, y;
int f[500][500]; // 存储到达每个点的最短步数
// 骑士的8个移动方向:(+1,+2), (+1,-2), (-1,+2), (-1,-2), (+2,+1), (+2,-1), (-2,+1), (-2,-1)
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1};

int main() {
    cin >> n >> m >> x >> y;
    // 初始化:所有点初始为“不可达(INF)”
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            f[i][j] = INF;
        }
    }
    f[x][y] = 0; // 起点步数为0

    queue<pair<int, int>> q;
    q.push({x, y}); // 起点入队

    while (!q.empty()) {
        auto [i, j] = q.front();
        q.pop();

        // 遍历8个方向
        for (int k = 0; k < 8; k++) {
            int ni = i + dx[k];
            int nj = j + dy[k];
            // 检查新位置是否在棋盘内,且未被访问过(或能更新为更短步数)
            if (ni >= 1 && ni <= n && nj >= 1 && nj <= m && f[ni][nj] == INF) {
                f[ni][nj] = f[i][j] + 1; // 步数+1
                q.push({ni, nj});        // 新位置入队,继续扩展
            }
        }
    }

    // 输出结果:INF改为-1,然后按格式输出
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (f[i][j] == INF) f[i][j] = -1;
            cout << f[i][j] << ' ';
        }
        cout << endl;
    }

    return 0;
}

A5 大小姐的古怪拆分

拆解最大素数因数,求最小素数因数就好了。点击即送,也是签到题。

#include <bits/stdc++.h>
using namespace std;
int main() {
    int a;
    cin >> a;
    for (int i = 2; i <= a; i++) 
        if (a % i == 0) { 
        cout << a / i;
        break;
    }
    return 0;
}

B0 四则运算进阶

做复杂了,想了一个类似于括号匹配的解法,用栈来维护字符串。

绝对不是正解但是也AC了。

image

#include<bits/stdc++.h>

using namespace std;
//我用栈写的,类似括号匹配的思路。
//怎么写的这么复杂
//为什么通过率这么高??
//输入的读取好像有点问题,还在调试
int priority(char op) {
    if (op == '+' || op == '-') return 1;
    if (op == '*' || op == '/') return 2;
    return 0;
}

void calculate(stack<double>& nums, stack<char>& ops) {
    if (nums.size() < 2 || ops.empty()) return; 
    // 确保栈有足够元素
    double b = nums.top(); nums.pop();
    double a = nums.top(); nums.pop();
    char op = ops.top(); ops.pop();
    double res;
    switch (op) {
        case '+': res = a + b; break;
        case '-': res = a - b; break;
        case '*': res = a * b; break;
        case '/': 
            if (b == 0) { 
                res = 0; 
            } else {
                res = a / b; 
            }
            break;
    }
    nums.push(res);
}

double evaluate(const string& s) {
    stack<double> nums;
    stack<char> ops;
    int i = 0;
    int n = s.size();
    if (n == 0) return 0; // 空表达式直接返回0

    while (i < n) {
        if (s[i] == ' ') {
            i++;
            continue;
        }

        if (s[i] == '+' || s[i] == '-') {
            bool isNegative = (s[i] == '-');
            // 负号
            if (isNegative && (i == 0 || s[i-1] == '(' || s[i-1] == '+' || s[i-1] == '-' || s[i-1] == '*' || s[i-1] == '/')) {
                i++;
                double num = 0.0;
                bool hasDot = false;
                double fraction = 0.1;
                // 提取
                while (i < n && (isdigit(s[i]) || s[i] == '.')) {
                    if (s[i] == '.') {
                        if (hasDot) break; // 避免多个小数点(如1.2.3)
                        hasDot = true;
                        i++;
                        continue;
                    }
                    if (!hasDot) {
                        num = num * 10 + (s[i] - '0');
                    } else {
                        num += (s[i] - '0') * fraction;
                        fraction *= 0.1;
                    }
                    i++;
                }
                nums.push(isNegative ? -num : num);
                continue;
            }
            // 加减
            while (!ops.empty() && ops.top() != '(' && priority(ops.top()) >= priority(s[i])) {
                calculate(nums, ops);
            }
            ops.push(s[i]);
            i++;
        } 
        // 提取正数或小数
        else if (isdigit(s[i]) || s[i] == '.') {
            double num = 0.0;
            bool hasDot = false;
            double fraction = 0.1;
            while (i < n && (isdigit(s[i]) || s[i] == '.')) {
                if (s[i] == '.') {
                    if (hasDot) break; // 避免多个小数点
                    hasDot = true;
                    i++;
                    continue;
                }
                if (!hasDot) {
                    num = num * 10 + (s[i] - '0');
                } else {
                    num += (s[i] - '0') * fraction;
                    fraction *= 0.1;
                }
                i++;
            }
            nums.push(num);
        } 
        // 左括号直接入栈
        else if (s[i] == '(') {
            ops.push(s[i]);
            i++;
        } 
        // 计算到左括号为止
        else if (s[i] == ')') {
            // 只计算到左括号
            while (!ops.empty() && ops.top() != '(') {
                calculate(nums, ops);
            }
            if (!ops.empty()) { // 确保栈非空再弹左括号
                ops.pop(); 
            }
            i++;
        } 
        // 乘除
        else if (s[i] == '*' || s[i] == '/') {
            while (!ops.empty() && ops.top() != '(' && priority(ops.top()) >= priority(s[i])) {
                calculate(nums, ops);
            }
            ops.push(s[i]);
            i++;
        } else {
            // 忽略非法字符
            i++;
        }
    }
    // 剩余操作符
    while (!ops.empty()) {
        calculate(nums, ops);
    }
    // nums非空
    return nums.empty() ? 0 : nums.top();
}

int main() {
    int t;
    cin >> t;
    // 搞了半天,太恶心了
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    
    while (t--) {
        string s;
      
        getline(cin, s);
        // 去除#
        if (!s.empty() && s.back() == '#') {
            s.pop_back();
        }
        // 计算并输出结果
        double result = evaluate(s);
        printf("%.4lf\n", result);
    }
    return 0;
}

B1 帮帮14行诗

image-20251020120407082

小清新贪心题

我写这道题的时候边界判断反复出问题,导致WA了好多次。警钟敲烂。

m[i] 为i点平衡伞数,f[i] 为i点的方案数,简单贪一下就OK了,自己看吧

#include<bits/stdc++.h>
using namespace std;
long long n,m[1000010],f[1000010];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>m[i];
		f[i]=0x3f3f3f3f;
	}
	f[1]=0;	
	for(int i=1;i<=n;i++)
	{
		if((i+m[i])<=n)
		{
			for(int j=i;j<=i+m[i];j++)
			{
				//if(w[j]!=0)
					f[j]=min(f[i]+1,f[j]);
			}
			//f[i+m[i]]=min(f[i]+1,f[i+m[i]]);
		}else{
			for(int j=i;j<=n;j++)
			{
				//if(w[j]!=0)
					f[j]=min(f[i]+1,f[j]);
			}
		//	f[n]=min(f[i]+1,f[n]);
		}
		
	}
	cout<<f[n];
	return 0;
}

B4 今州城改造计划

招新就上图论吗,有意思。

image

image

image-20251020115747510

思路是Dijskra,随处优化,我写最简单的Dijskra只能获得50pts。唉。

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

typedef long long ll;
const int MAXN = 1e5 + 5;
const int MAXM = 2e5 + 5;
const ll INF = LLONG_MAX;

struct Edge {
    int to, w, next;
} edges[MAXM * 2];
int head[MAXN], idx = 0;

ll dist[MAXN];
int N, M, C;
vector<pair<ll, int>> edge_info;
vector<ll> prefix_sum;

void add_edge(int u, int v, int w) {
    edges[idx].to = v;
    edges[idx].w = w;
    edges[idx].next = head[u];
    head[u] = idx++;

    edges[idx].to = u;
    edges[idx].w = w;
    edges[idx].next = head[v];
    head[v] = idx++;
}

void dijkstra() {
    priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
    fill(dist, dist + MAXN, INF);
    dist[1] = 0;
    pq.emplace(0, 1);

    while (!pq.empty()) {
        auto [d, u] = pq.top();
        pq.pop();
        if (d > dist[u]) continue;

        for (int i = head[u]; i != -1; i = edges[i].next) {
            int v = edges[i].to;
            int w = edges[i].w;
            if (dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                pq.emplace(dist[v], v);
            }
        }
    }
}

int main() {
	//加速加速加速加速
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    fill(head, head + MAXN, -1);
    cin >> N >> M >> C;

    for (int i = 0; i < M; ++i) {
        int A, B, D;
        cin >> A >> B >> D;
        add_edge(A, B, D);
    }

    dijkstra();

    edge_info.reserve(M);
    for (int i = 0; i < idx; i += 2) {
        int A = edges[i].to;
        int B = edges[i ^ 1].to;
        int D = edges[i].w;
        ll max_d = max(dist[A], dist[B]);
        edge_info.emplace_back(max_d, D);
    }

    sort(edge_info.begin(), edge_info.end());

    prefix_sum.resize(M + 1, 0);
    for (int i = 0; i < M; ++i) {
        prefix_sum[i + 1] = prefix_sum[i] + edge_info[i].second;
    }

    vector<ll> dists;
    for (int i = 1; i <= N; ++i) {
        dists.push_back(dist[i]);
    }
    sort(dists.begin(), dists.end());
    dists.erase(unique(dists.begin(), dists.end()), dists.end());

    ll min_total = LLONG_MAX;
    for (ll X : dists) {
        auto it = upper_bound(edge_info.begin(), edge_info.end(), make_pair(X, INT_MAX));
        int cnt = edge_info.end() - it;
        ll repair = prefix_sum[M] - prefix_sum[M - cnt];
        ll total = C * X + repair;
        if (total < min_total) {
            min_total = total;
        }
    }

    cout << min_total << endl;
    return 0;
}

本人能力受限只能写这么多了,剩下的题没写出来qwq

深大还是有很多大佬在的,膜拜。

posted @ 2025-10-20 12:03  Miya555  阅读(85)  评论(0)    收藏  举报