【解题报告】2015ACM/ICPC亚洲区沈阳站

题目链接

B. Bazinga(HDU5510)

思路

设第i个字符串存储在ss[i][]中。本题最直观最朴素的做法是枚举两个字符串ss[i]和ss[j] (i+1j) ,再用KMP算法匹配这两个字符串。首先从大到小枚举j,若对某个ss[j]存在某个ss[i]不是其子串,则立即可以得到答案j。但是,这样做的时间复杂度太高,因此行不通。不难看出,之所以复杂度这么高,是因为对任意的ss[i]和ss[j],朴素算法都要对其进行匹配。这是无疑是一种浪费。实际上我们只需要匹配一次就够了。
我的做法是,先令所有的ss[i] (in) 与ss[n]进行一次匹配,若出现一次匹配失败则答案就是n。若全部匹配成功则可以得到一个重要的结论:所有的ss[i] (in) 都是ss[n]的子串。也就是说我们在往后的比较中可以用ss[i] (in) 在ss[n]中的位置信息(用区间来表示)取代ss[i]的字符串内容来判断这个字符串是不是另一个字符串的子串。
例如ss[1] = “ab”, ss[2] = “bc”, ss[3] = “abc”。在ss[1],ss[2]同ss[3]的比较中发现,ss[1]和ss[2]都是ss[3]的子串。对应的位置信息为 [0,1] [1,2] ,由于前者不包含在后者中,因此答案为2。

代码:
#include <cstdio>
#include <cstring>

const int maxn = 5e2 + 5, maxLen = 2e3 + 5;
char ss[maxn][maxLen];
int t, n, ans, next[maxLen], a[maxn][2];

void getNext(char* p) {
    int lp = strlen(p);
    next[0] = -1;
    for(int j=0, k=-1; j < lp-1;) {
        if(k == -1 || p[j] == p[k]) {
            j++, k++;
            if(p[j] != p[k]) next[j] = k;
            else next[j] = next[k];
        }
        else k=next[k];
    }
}

int kmp(char* s, char* p) {
    int i = 0, j = 0;
    int ls = strlen(s), lp = strlen(p);
    for(; i < ls && j < lp;) {
        if(j == -1 || s[i] == p[j]) i++, j++;
        else j = next[j];
    }
    if(j == lp) return i - j;
    else return -1;
}

int main() {
    scanf("%d", &t);
    for(int kase = 1; kase <= t; kase++) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%s", ss[i]);
        }
        int len = strlen(ss[n]);
        bool exist = false;
        // 判断n是否是答案
        for(int i = 1; i < n; i++) {
            getNext(ss[i]);
            int res = kmp(ss[n], ss[i]);
            if(res == -1) {
                exist = true;
                break;
            }
            // 记录位置信息
            a[i][0] = res;
            a[i][1] = res + strlen(ss[i]) - 1;
        }
        if(exist) {
            printf("Case #%d: %d\n", kase, n);
            continue;
        }
        ans = -1;
        // 枚举两个字符串,比较它们的位置信息
        for(int i = n - 1; i > 0; i--) {
            for(int j = 1; j < i; j++) {
                if(a[i][0] > a[j][0] || a[i][1] < a[j][1]) {
                    ans = i;
                    i = 0;
                    break;
                }
            }
        }
        printf("Case #%d: %d\n", kase, ans);
    }
    return 0;
}

D. Pagodas(HDU 5512)

思路

根据贝祖定理(扩展欧几里德算法的理论基础),对于任意两个整数 a,b ,存在 x,y 使得

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值