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

来源:互联网 发布:淘宝爆款打造花钱 编辑:程序博客网 时间:2024/06/10 01:51

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 : bint 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 1e9int 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 longint 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 longint 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;}
0 0
原创粉丝点击