2016年乐山师范学院程序设计大赛解题报告

A:切割回文

先计算出所有子串是否是回文串,这个步骤的时间复杂度应该是O(N*N),然后再进行动态规划,当前的最少切割是有前面的最少切割所推导出来的,总的最坏时间复杂度是O(N *N)。

#include <stdio.h>
#include <string.h>
#define MAXN 1000
#define MIN(a, b) (a < b ? a : b)
int sub[MAXN][MAXN];
void preprocess(char str[], int len) {
    int a, b, l, r;
    for (a = 0; a < MAXN; ++a) {
        for (b = 0; b < MAXN; ++b) {
            sub[a][b] = 0;
        }
    }
    for (a = 0; a < len; ++a) {
        l = a, r = a;
        while (0 <= l && r < len && str[l] == str[r]) {
            sub[l][r] = 1;
            l -= 1, r += 1;
        }
        l = a, r = a + 1;
        while (0 <= l && r < len && str[l] == str[r]) {
            sub[l][r] = 1;
            l -= 1, r += 1;
        }
    }
}
int main() {
    int T, dp[1000], len, a, b, c;
    char str[1001];
    scanf("%d", &T);
    while (T--) {
        scanf("%s", str);
        len = strlen(str);
        preprocess(str, len);
        //for (a = 0; a < MAXN; ++a) dp[a] = 0;
        dp[0] = 1;
        for (a = 1; a < len; ++a) {
            dp[a] = dp[a - 1] + 1;
            for (b = a - 1; b >= 0; --b) {
                if (sub[b][a]) {
                    if (b == 0) dp[a] = 1;
                    else dp[a] = MIN(dp[a], dp[b - 1] + 1);
                }
            }
        }
        printf("%d\n", dp[len - 1] - 1);
    }
    return 0;
}

B:特殊密码锁

每个按钮最多按一次,所以当前按钮的按或不按,只取决于当前按钮的状态和前一个按钮的状态,以此来进行下一步搜索,边缘情况特殊处理即可。可能我的状态表示方法略有欠妥,可自行斟酌。

#include <stdio.h>
#include <string.h>
#define INF 30
#define MIN(a, b) (a < b ? a : b)
char str[30], check[30];
void change(int pos, int len) {
    if (pos == 0) {
        if (str[pos] == '1') str[pos] = '0';
        else str[pos] = '1';
        if (pos + 1 == len) return;
        if (str[pos + 1] == '1') str[pos + 1] = '0';
        else str[pos + 1] = '1';
        return;
    }
    if (str[pos - 1] == '1') str[pos - 1] = '0';
    else str[pos - 1] = '1';
    if (str[pos] == '1') str[pos] = '0';
    else str[pos] = '1';
    if (pos + 1 == len) return;
    if (str[pos + 1] == '1') str[pos + 1] = '0';
    else str[pos + 1] = '1';
    return;
}
int solve(int pos, int len, int step) {
    int res = INF, tmp;
    if (pos == len) {
        return str[pos - 1] == check[pos - 1] ? step : INF;
    }
    if (pos == 0) {
        tmp = solve(pos + 1, len, step);
        res = MIN(res, tmp);
        change(pos, len);
        tmp = solve(pos + 1, len, step + 1);
        res = MIN(res, tmp);
        change(pos, len);
        return res;
    }
    if (str[pos - 1] == check[pos - 1]) {
        tmp = solve(pos + 1, len, step);
        res = MIN(res, tmp);
    } else {
        change(pos, len);
        tmp = solve(pos + 1, len, step + 1);
        res = MIN(res, tmp);
        change(pos, len);
    }
    return res;
}
int main() {
    int res = INF, len;
    while (scanf("%s%s", str, check) != EOF) {
        len = strlen(str);
        if (len != strlen(check)) printf("impossible\n");
        res = solve(0, len, 0);
        if (res == INF) printf("impossible\n");
        else printf("%d\n", res);
    }
    return 0;
}

C:最佳序列

目前有一个最坏时间复杂度为O(N*logN *logN)的思路,代码没有敲完,有兴趣讨论的朋友可以私信我。

D:字符串判等

先全部大写转小写,然后逐一去掉空格。

#include <stdio.h>
#include <string.h>

void to_lowercase(char *str) {
    int a, len = strlen(str);
    for (a = 0; a < len; ++a) {
        if (str[a] < 97 && str[a] != ' ') str[a] += 32;
    }
}

void remove_space(char *str) {
    int a, b = 0, len = strlen(str);
    for (a = 0; a < len; ++a) {
        if (str[a] != ' ') str[b++] = str[a];
    }
    for (a = b; a < len; ++a) str[a] = 0;
}

int main() {
    char stra[10000], strb[10000];
    int a, lena, lenb, res = 1;
    gets(stra), gets(strb);
    to_lowercase(stra), to_lowercase(strb);
    remove_space(stra), remove_space(strb);
    lena = strlen(stra), lenb = strlen(strb);
    if (lena != lenb) res = 0;
    //printf("%s\n%s\n", stra, strb);
    for (a = 0; a < (lena & lenb); ++a) {
        if (stra[a] != strb[a]) res = 0;
    }
    printf("%s\n", (res ? "YES" : "NO"));
    return 0;
}

E:区间合并

先排序,再判断所有区间是否能连接起来。
但是介于数据范围,也可以用哈希解决此题。O(N * N)的最坏时间复杂度理论上是过不了的,但是最后确实有人这样做,然后拿到了Accepted,这就不科学了。

#include <stdio.h>
typedef struct pair {
    int l, r;
}pair;
int compare(const void *a, const void *b) {
    return ((pair *)a)->l - ((pair *)b)->l;
}
int main() {
    int a, b, l, r, ok = 1, N;
    pair region[50000];
    scanf("%d", &N);
    for (a = 0; a < N; ++a) {
        scanf("%d%d", &region[a].l, &region[a].r);
    }
    qsort(region, N, sizeof(pair), compare);
    l = region[0].l;
    r = region[0].r;
    for (a = 1; a < N; ++a) {
        if (r < region[a].l) {
            ok = 0;
            break;
        }
        r = r < region[a].r ? region[a].r : r;
    }
    if (ok) printf("%d %d\n", l, r);
    else printf("no\n");
    return 0;
}

F:字符环

这道题的重点在于环,本来应该是一道简单题目的,可能大多数同学都缺少这类型题目的处理经验吧。介于这题的数据范围很小,解决这道题目,只需将将每个串加倍,然后暴力去找到最长的公共子串即可。

#include <stdio.h>
#include <string.h>
#define MAX(a, b) a > b ? a : b
int main() {
    char stra[10000], strb[10000];
    int a, b, tmp, res = 0, lena, lenb;
    scanf("%s%s", stra, strb);
    lena = strlen(stra), lenb = strlen(strb);
    for (a = 0; a < lena; ++a) stra[a + lena] = stra[a];
    for (a = 0; a < lenb; ++a) strb[a + lenb] = strb[a];
    stra[lena * 2] = 0, strb[lenb * 2] = 0;
    //printf("%s\n%s\n", stra, strb);
    for (a = 0; a < lena * 2; ++a) {
        for (b = 0; b < lenb * 2; ++b) {
            tmp = 0;
            while (tmp + a < lena * 2 &&
                   tmp + b < lenb * 2 &&
                   stra[tmp + a] == strb[tmp + b] &&
                   tmp < lena && tmp < lenb) tmp += 1;
            res = MAX(res, tmp);
        }
    }
    printf("%d\n", res);
    return 0;
}

G:分段函数

这场比赛,没有接触过程序设计竞赛的同学来讲,还是有很多道签到题,这题就是其中一道。

#include <stdio.h>
int main() {
    double N, fN;
    scanf("%lf", &N);
    if (0 <= N && N < 5) fN = -N + 2.5;
    else if (5 <= N && N < 10) fN = 2 - 1.5 * (N - 3) * (N - 3);
    else if (10 <= N && N < 20) fN = N * 1.0 / 2 - 1.5;
    printf("%.3lf\n", fN);
    return 0;
}

H:最小新整数

一个不足十位的数,没有0,删去K位。直接枚举出所有可能的数,找到一个最小的。枚举出所有的可能的数最多也就C(10,5)个,所以,应该只是考察代码能力吧。

#include <stdio.h>
#include <string.h>
#define MIN(a, b) (a < b ? a : b)
#define INF 1e9
int solve(char *number, int len, int n, int K) {
    int a, b;
    for (a = 0; a < len; ++a) {
        if (n >> a & 1) continue;
        K -= 1;
    }
    if (K) return INF;
    for (a = 0, b = 0; a < len; ++a) {
        if (n >> a & 1) {
            b = b * 10 + (number[a] - '0');
        }
    }
    return b;
}
int main() {
    int T, K, len, res, a, b;
    char number[10];
    scanf("%d", &T);
    while (T--) {
        scanf("%s%d", number, &K);
        len = strlen(number);
        res = INF;
        for (a = 0; a < 1 << len; ++a) {
            b = solve(number, len, a, K);
            res = MIN(res, b);
        }
        printf("%d\n", res);
    }
    return 0;
}

I:健康生活每一天

签到题。

#include <stdio.h>
int main() {
    int N, x, ok;
    double t;
    char flag[5];
    scanf("%d", &N);
    while (N--) {
        scanf("%lf%d%s", &t, &x, flag);
        ok = 1;
        if (t < 7.0 || t > 8.0) ok = 0;
        if (x < 1500) ok = 0;
        if (flag[0] == 'N' && flag[1] == 'o') ok = 0;
        //printf("flag: %s\n", flag);
        printf(ok ? "Yes\n" : "No\n");
    }
    return 0;
}

J:3个数排序

签到题。

#include <stdio.h>
void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}
int main() {
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    if (a < b) swap(&a, &b);
    if (a < c) swap(&a, &c);
    if (b < c) swap(&b, &c);
    printf("%d %d %d\n", a, b, c);
    return 0;
}

K:寻找配对数

先排序,然后两个循环枚举两个不同的数,再通过二分查找去判断集合中是否存在这个两个数的乘积,O(N *N *logN)的最坏时间复杂度就能拿到Accepted。注意爆int,注意去重。

#include <stdio.h>
#define ll long long

int compare(const void *a, const void *b) {
    return (int)((*(ll *)a) - (*(ll *)b));
}

int find(ll *arr, int len, ll val) {
    int l = 0, r = len, mid;
    while (l < r) {
        mid = l + (r - l) / 2;
        if (val == arr[mid]) return 1;
        if (val < arr[mid]) r = mid;
        else l = mid + 1;
    }
    return val == arr[l];
}

int main() {
    int N, res = 0;
    ll arr[1000];
    int a, b, c;
    scanf("%d", &N);
    for (a = 0; a < N; ++a) scanf("%lld", arr + a);
    qsort(arr, N, sizeof(arr[0]), compare);
    for (a = 0; a < N; ++a) {
        for (b = a + 1; b < N; ++b) {
            if (arr[a] != 1 && find(arr, N, arr[a] * arr[b])) {
                res += 1;
            }
        }
    }
    printf("%d\n", res);
    return 0;
}

L:组合数

这题有很多种不同的解法,主要在于自己怎么推导公式。

#include <stdio.h>
#define ll long long
int main() {
    int N, M;
    ll arr[21], a;
    for (arr[0] = arr[1] = 1, a = 2; a <= 20; ++a) {
        arr[a] = arr[a - 1] * a;
    }
    while (scanf("%d%d", &N, &M) != EOF) {
        if (N < M) {
            printf("0\n");
            continue;
        }
        printf("%lld\n", arr[N] / arr[N - M] / arr[M]);
    }
    return 0;
}

M:分解质因数

知道有的同学肯定会先筛选素数,但是如果仔细想想,确实是没有必要啊。

#include <stdio.h>
int main() {
    int N, a;
    scanf("%d", &N);
    printf("%d=", N);
    for (a = 2; a <= N; ++a) {
        while (N % a == 0) {
            printf("%d", a);
            if ((N /= a) != 1) printf("*");
        }
    }
    printf("\n");
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值