码迷,mamicode.com
首页 > 其他好文 > 详细

P1026 统计单词个数 【dp】

时间:2020-03-21 12:42:57      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:要求   false   its   部分   描述   递推   default   code   temp   

题目描述

给出一个长度不超过 200200 的由小写英文字母组成的字母串(该字串以每行 2020 个字母的方式输入,且保证每行一定为 2020 个)。要求将此字母串分成 kk 份,且每份中包含的单词个数加起来总数最大。

每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串 this 中可包含 this 和 is,选用 this 之后就不能包含 th

单词在给出的一个不超过 66 个单词的字典中。

要求输出最大的个数。

输入格式

每组的第一行有两个正整数 p,kp,k。 pp 表示字串的行数,kk 表示分为 kk 个部分。

接下来的 pp 行,每行均有 2020 个字符。

再接下来有一个正整数 ss,表示字典中单词个数。 接下来的 ss 行,每行均有一个单词。

输出格式

11个整数,分别对应每组测试数据的相应结果。

输入输出样例

输入 #1
1 3
thisisabookyouareaoh
4
is
a
ok
sab
输出 #1
7

技术图片

 

 思路

  题意有个地方说的比较模糊,就是重叠的情况下的影响。

  实际上是用了this可以再选is,但是不能再选第一个字母t,也就是选满了main_len之后就不能选了。

  大概懂了之后就知道这是一个递推找字符串的子串里满足能在字典中找到单词且能出现几个单词。

  用 sum [ i ] [ j ] 来表示主字符串里 i ~ j 区间内有几个单词。

  用 f [ i ] [ j ] 来表示到第 i 个字符切成 j 段能获得的最大单词数。

  显然可以如下转移:

        f [ i ] [ k ] = max ( f [ i ] [ k ] , f [ j ] [ k - 1] + sum [ i - 1 ] [ j ] ) ; 其中 k ∈ [ 2, min ( k, j + 1 ) ] ;

 

CODE

 

 
#include <bits/stdc++.h>
#define dbg(x) cout << #x << "=" << x << endl
#define eps 1e-8
#define pi acos(-1.0)

using namespace std;
typedef long long LL;

const int inf = 0x3f3f3f3f;

template<class T>inline void read(&res)
{
    char c;T flag=1;
    while((c=getchar())<0||c>9)if(c==-)flag=-1;res=c-0;
    while((c=getchar())>=0&&c<=9)res=res*10+c-0;res*=flag;
}

namespace _buff {
    const size_t BUFF = 1 << 19;
    char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
    char getc() {
        if (ib == ie) {
            ib = ibuf;
            ie = ibuf + fread(ibuf, 1, BUFF, stdin);
        }
        return ib == ie ? -1 : *ib++;
    }
}

int qread() {
    using namespace _buff;
    int ret = 0;
    bool pos = true;
    char c = getc();
    for (; (< 0 || c > 9) && c != -; c = getc()) {
        assert(~c);
    }
    if (== -) {
        pos = false;
        c = getc();
    }
    for (; c >= 0 && c <= 9; c = getc()) {
        ret = (ret << 3) + (ret << 1) + (^ 48);
    }
    return pos ? ret : -ret;
}

int p, k;

string a, b;
string ss[15];

int sum[1000][1000];
int f[1000][1000];

int main()
{
    read(p);read(k);
    for ( int i = 1; i <= p; ++) {
        cin >> b;
        a += b;
    }
    int main_len = a.size();
    int n;
    read(n);
    vector<int> len(+ 7);
    for ( int i = 1; i <= n; ++) {
        cin >> ss[i];
        len[i] = ss[i].size();
    }
    for ( int i = 0; i < main_len; ++) {
        for ( int j = i; j < main_len; ++) {//todo:枚举子段
            for ( int k = i; k <= j; ++) {
                int ok = 1;
                for ( int z = 1; z <= n; ++) {
                    if(+ len[z] - 1 > j)
                        continue;
                    for ( int w = 0; w < len[z]; ++) {
                        if(== len[z] - 1 && a[+ w] == ss[z][w]) {
                            ok = 0;
                            break;
                        }
                        if(a[+ w] != ss[z][w]) {
                            break;
                        }
                    }
                    if(!ok)
                        break;
                }
                if(!ok) {
                    sum[i][j]++;
                }
            }
        }
    }
    // for ( int i = 0; i < main_len; ++i ) {
    //     for ( int j = 0; j < main_len; ++j ) {
    //         printf("sum[%d][%d]:%d\n",i, j, sum[i][j]);
    //     }
    // }
    for ( int i = 0; i < main_len; ++) {
        f[i][1] = sum[0][i];
        for ( int j = 0; j < i; ++) {
            for ( int k = 2; k <= min(k, j + 1); ++) {
                f[i][k] = max(f[i][k], f[j][- 1] + sum[+ 1][i]);
            }
        }
    }
    cout << f[main_len - 1][k] << endl;
    return 0;
}

P1026 统计单词个数 【dp】

标签:要求   false   its   部分   描述   递推   default   code   temp   

原文地址:https://www.cnblogs.com/orangeko/p/12537449.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!