[topic] 情報オリンピック2007年度国内本選問題2

中高生向けの情報オリンピック国内本選2007年度問題2です。

問題文(下記PDFの4ページ目)
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/2008-ho.pdf
コンテスト概要
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/index.html
サンプルデータ(出題時に公開)
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/joi2008.zip
採点データ(出題時に非公開)
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/data.zip

「問題ごとに、プログラムの実行時間(や使用メモリ量)に制限が設定されています。」にご注意ください。本問では、制限時間1秒、メモリ制限64MBとなっています。

出題時はサンプルデータのみが公開され、採点は、採点データによる、自動採点にて行われます。

実際のコンテストでは、予選通過者48名が対象となっていて、100点満点中38点以上とった、16名が本選通過です。

Posted feedbacks - C++

ブログのほうでリクエストがありましたので書き込ませていただきます。
公式ジャッジデータで時間内に正答することは一応確認しています。
少しでも参考になれば幸いです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<iostream>
#include<vector>

#define DEBUG(c) cerr<<"> "<<#c<<" = "<<c<<endl;

using namespace std;

int main()
{
    string s,t; cin>>s>>t;
    vector<vector<int> > dp(s.size(),vector<int>(t.size(),0));
    
    int res=0;
    for(int i=0;i<s.size();i++)
    {
        for(int j=0;j<t.size();j++)
        {
            if(i==0 || j==0)
            {
                if(s[i]==t[j])
                    dp[i][j]=1;
            }
            else if(s[i]==t[j])
                res=max(res,dp[i][j]=dp[i-1][j-1]+1);
        }
    }
    
    cout<<res<<endl;
    
    return 0;
}

いくつかのデータで1秒制限を満たしてないと思いますが、とりあえず接尾辞配列で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

struct char_at
{
    const char* s;

    static size_t i;

    explicit char_at(const char* s_) : s(s_) {}

    operator bool() const { return s[i]; }

    friend bool operator==(const char_at& lhs, const char_at& rhs)
    {
        return lhs.s[i] == rhs.s[i];
    }

    friend bool operator<(const char_at& lhs, const char_at& rhs)
    {
        return lhs.s[i] < rhs.s[i];
    }

    friend ostream& operator<<(ostream& out, const char_at& at) // debug
    {
        return out << (at.s + i);
    }
};

size_t char_at::i;

bool compare_s(const char_at& lhs, const char_at& rhs)
{
    return strcmp(lhs.s, rhs.s) < 0;
}

int main()
{
    string s1; getline(cin, s1);

    string s2; getline(cin, s2);

    vector<char_at> v;

    for (const char* p = s1.c_str(); *p; ++p)
    {
        v.push_back(char_at(p));
    }

    sort(v.begin(), v.end(), compare_s);

    size_t result = 0;

    for (const char* p = s2.c_str(); *p; ++p)
    {
        char_at at(p);

        pair<vector<char_at>::iterator, vector<char_at>::iterator>
            r = make_pair(v.begin(), v.end());

        for (char_at::i = 0; ; ++char_at::i)
        {
            r = equal_range(r.first, r.second, at);

            while (r.first != r.second && !*r.first)
            {
                ++r.first;
            }

            if (r.first == r.second || !at)
            {
                break;
            }
        }

        result = max(result, char_at::i);
    }

    cout << result << endl;
}

両方の文字列から接尾辞配列を作って処理するようにしたら、若干高速化しました。(手元で判定データ 2-6 が 17秒 => 10秒。このマシンはPen2-266で遅いんですが、それを差し引いても大会のマシンで1秒制限を満たすか怪しいです)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <string.h> // strcmp()

#define REP(i, b, e) for (size_t i = b; i < e; ++i)

bool compare_str(const char* s1, const char* s2)
{
    return strcmp(s1, s2) < 0;
}

void make_suffix_array(const std::string& s, std::vector<const char*>& v)
{
    v.resize(s.size());

    REP(i, 0, s.size())
    {
        v[i] = s.c_str() + i;
    }

    std::sort(v.begin(), v.end(), compare_str);
}

typedef std::vector<const char*>::const_iterator Iter;

void skip_empty_string(Iter& beg, Iter end, size_t depth)
{
    while (beg != end && (*beg)[depth] == '\0')
    {
        ++beg;
    }
}

void find_range(Iter& beg, Iter& end, size_t depth, char c)
{
    while (beg != end && (*beg)[depth] < c)
    {
        ++beg;
    }

    Iter cur = beg;

    while (cur != end && (*cur)[depth] == c)
    {
        ++cur;
    }

    end = cur;
}

void traverse(Iter beg1, Iter end1, Iter beg2, Iter end2, size_t depth, size_t& max_depth)
{
    skip_empty_string(beg1, end1, depth);

    skip_empty_string(beg2, end2, depth);

    while (beg1 != end1 && beg2 != end2)
    {
        const char c = (*beg1)[depth];

        Iter the_beg1 = beg1, the_end1 = end1;

        find_range(the_beg1, the_end1, depth, c);

        Iter the_beg2 = beg2, the_end2 = end2;

        find_range(the_beg2, the_end2, depth, c);

        if (the_beg1 != the_end1 && the_beg2 != the_end2)
        {
            max_depth = std::max(max_depth, depth + 1);

            traverse(the_beg1, the_end1, the_beg2, the_end2, depth + 1, max_depth);
        }

        beg1 = the_end1;

        beg2 = the_end2;
    }
}

int main()
{
    std::string s1, s2;

    std::getline(std::cin, s1);

    std::getline(std::cin, s2);

    std::vector<const char*> v1, v2;

    make_suffix_array(s1, v1);

    make_suffix_array(s2, v2);

    size_t max_depth = 0;

    traverse(v1.begin(), v1.end(), v2.begin(), v2.end(), 0, max_depth);

    std::cout << max_depth << std::endl;
}

Index

Feed

Other

Link

Pathtraq

loading...