2021年合肥学院程序设计竞赛

2021年合肥学院校赛题解

A.我爱合院

思路

​ 直接输出"HFUU"即可。

代码:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "HFUU";
    return 0;
}

B.简单的工资发放问题

思路

第一天的工资为1,后面两天的工资为2, 2,后面三天的工资为3,3,3......
数据范围为1 - 10000,方法很多, 我们可以先预处理出每天的工资,然后循环一次累加每天的工资即可。时间复杂度O(n)

代码

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 10010;

LL a[N];
int n;
int main()
{
    int n;
    scanf("%d", &n);
    int qwq = 0;
    int flag = 1;
    for(int i = 1; i <= n; i ++ )
    {
        a[i] = flag;
        ++ qwq;
        if(qwq == flag)
        {
            flag ++;
            qwq = 0;
        }
    }
    LL ans = 0;
    for(int i = 1; i <= n; i ++ ) ans += a[i];
    printf("%lld",ans);
    return 0;
}

C.简单的计算几何问题

思路

本题我们可以对所有的点求一个凸包,答案就是凸包的周长。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define x first
#define y second

using namespace std;
const int  N = 10010;

typedef pair<double,double> PDD;
int n;
PDD q[N];
int stk[N];
bool st[N];

PDD operator-(PDD a, PDD b)
{
    return {a.x - b.x, a.y - b.y};
}

double cross(PDD a, PDD b)
{
    return a.x * b.y - b.x * a.y;
}

double area(PDD a, PDD b, PDD c)
{
    return cross(b - a, c - a);
}

double get_dist(PDD a, PDD b)
{
    double xx = a.x - b.x;
    double yy = a.y - b.y;
    return sqrt(xx * xx + yy * yy);
}

double Andrew()
{
    sort(q + 1, q + 1 + n);
    int top = 0;
    for(int i = 1; i <= n; i ++ )
    {
        while(top >= 2 && area(q[stk[top - 1]], q[stk[top]], q[i]) <= 0)
        {
            if(area(q[stk[top - 1]], q[stk[top]], q[i]) < 0)
                st[stk[top -- ]] = false;
            else top --;
        }
        stk[ ++ top] = i;
        st[i] = true;
    }
    st[1] = false;
    for(int i = n; i >= 1; i -- )
    {
        if(st[i]) continue;
        while(top >= 2 && area(q[stk[top - 1]], q[stk[top]], q[i]) <= 0)
        {
            if(area(q[stk[top - 1]], q[stk[top]], q[i]) < 0)
                st[stk[top -- ]] = false;
            else top --;
        }
        stk[++ top] = i;
        st[i] = true;
    }
    double res = 0;
    for(int i = 2; i <= top; i ++ )
        res += get_dist(q[stk[i]], q[stk[i - 1]]);
    return res;
}

int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++ ) scanf("%lf %lf",&q[i].x, &q[i].y);
    double res = Andrew();
    printf("%.2lf", res);
    return 0;
}

D.简单的理财问题

思路:

本题是纯模拟题。
整个过程是确定的,从前往后依次模拟整个流程即可。

模拟过程中记录如下几个值:

total: 存在姐姐那里的总钱数;
remain: bs当前剩在自己手里的钱数;
cur:读入的值,表示当前这个月的生活开销

依次枚举每个月,对于当前这个月,首先判断总共能拿到的钱数是否够用,即判断:

cur + 300 >= cur是否成立;
如果够用,则将整百部分交给姐姐,自己剩下最多两位数的钱。

最后的总钱数是:total * 12 + remain

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    int total = 0, remain = 0;
    for (int i = 1; i <= 12; i ++ )
    {
        int cur;
        cin >> cur;
        if (remain + 300 < cur)
        {
            total = -i;
            break;
        }
        remain += 300 - cur;
        total += remain / 100 * 120;
        remain %= 100;
    }

    if (total >= 0) total += remain;

    cout << total << endl;

    return 0;
}

E.简单的路径规划问题

思路

裸的最短路问题,方法很多,套朴素Dijkstra都能过,堆优化的当然更好。
朴素Dijkstra的时间复杂度 \(O(n^2)\)

优化的Dijkstra的时间复杂度为\(O(nlogn)\)

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510;

int n, m;
int g[N][N];
int dist[N];
bool st[N];

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main()
{
    scanf("%d%d", &n, &m);

    memset(g, 0x3f, sizeof g);
    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);

        g[a][b] = min(g[a][b], c);
    }

    printf("%d\n", dijkstra());

    return 0;
}

F.简单的字符串问题

思路:

本题要求长度大于\(1\)且最短的回文串,只有三种情况:
\(1\).字符串里面出现连续两个相同的字符 , \(exp: .....aa.....\) 答案是$ 2 $
\(2\).字符串中出现长度为3的回文串,例如: $...qwq... $答案是 \(3\)
\(3\).字符串中只有长度为1的回文串例如:\(abcdefg\),答案是 \(-1\)
其余的回文串如果存在则一定长于第一第二种情况,所以答案只有\(2, 3, -1\)
时间复杂度为\(O(n)\)\(n\)为字符串的长度。

代码:

#include <cstring>
#include <iostream>

using namespace std;

string s;

int main()
{
    cin >> s;
    int len = s.length();
    for(int i = 1; i < len; i ++ )
    {
        if(s[i] == s[i - 1]) {
            printf("2\n");
            return 0;
        }
    }
    for(int i = 1; i < len; i ++ )
    {
        if(s[i - 1] == s[i + 1] && i + 1 < len){
            printf("3\n");
            return 0;
        }
    }
    printf("-1\n");
    return 0;
}

G.简单的排序问题

思路:

本题的思路很明显,先把所有的时间段排个序,然后选择时间段较长的即可,排序的话大部分排序方式都能过,冒泡也能过。
时间复杂度是关于你的排序方式,冒泡为\(O(n^2)\)或者快排是\(O(nlogn)\)

代码:

#include <stdio.h>
#define N 10010
int main()
{
    int n;
	int a[N];
	scanf("%d",&n);
	for(int i = 1; i<= n; i ++ ) scanf("%d",&a[i]);
	int temp, i, j;

	for (i = 1; i <= n; i++)    //进行9次比较
		for (j = 1; j <= n - i; j++)   //在每次中进行10-i-1次比较
			if (a[j] > a[j + 1])      //按升序排序,降序用<
			{
				temp = a[j + 1];      //交换相邻的两个元素
				a[j + 1] = a[j];
				a[j] = temp;
			}

    int sum = 0;
	for (i = n / 2 + 1; i <= n; i++)  sum += a[i];
	printf("%lld", sum);
}

H.简单的桌游问题

思路:

题意可以理解成不能出现边长都为1的三角形路径,根据这个要求,可以发现,当将一个元素作为起点,遍历剩余的棋子作为一个个终点,这样的连接方式是符合题意要求的。同时,为了保证答案的最大化,我们可以将更多的棋子作为起点方,剩余的棋子当作终点方,显然当起点和终点的棋子差距最小时,答案是最大的,所以本题可以等价成左右两排数求最多的连接数。
时间复杂度为\(O(1)\).

代码:

#include <bits/stdc++.h>
using namespace std;
 
typedef long long LL;
const int mod = 998244353;
 
int main() {
    int n;
    while (cin >> n)
    cout << (n / 2) * (n - n / 2) << endl;
    return 0;
}

I.简单的数据结构问题

思路:

本题的每组数据的答案都在一个不断更新的长度为一整天的数组中,注意到每次输入时的ti是递增的,所以可以类比成一个滑动的窗口不断单调滑动,所以本题我们需要用到队列来处理滑动窗口,用队列中队头和队尾的更新来模拟窗口的滑动,在滑动时不断更新数组储存的国籍数据。
时间复杂度\(O(K)\)

代码:

#include<iostream>
using namespace std;
int s,i,n,t,k,r,w[100001],x[300002],y[300002];

int main(){
    cin>>n;
    while(n--){
        cin>>t>>k;
        while(k--){
            y[++r]=t;cin>>x[r];
            if(!w[x[r]])s++;
            w[x[r]]++;
        }
        while(t-y[i]>=86400)
            if(!--w[x[i++]])s--;
        cout<<s<<endl;
    }
    return 0;
}

J.合院生日快乐

思路:

输出$ n - 40 + 2020$即可

代码:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    cin >> n;
    cout << n  - 40 + 2020 << endl;
    return 0;
}
posted @ 2021-12-19 17:08  bigstrength  阅读(213)  评论(0编辑  收藏  举报