点我写题
题目描述
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份( 1 < k ≤ 40 ),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。单词在给出的一个不超过6个单词的字典中。要求输出最大的个数。
题意个人补充:必须恰好分成k份(所以下面初始化成负无穷先),每份不能为空。
先处理出i-j区间的最多单词数(一开始我想用区间dp求,但是没考虑左端的合法字符串下标超过了区间右端j,导致转移不合法,然后只过了75%,敲响警钟!!),倒着转移,这样能保证每个开头只用了一次,然后再定义a[i][j],仅考虑前i个字符划分成j份的最大单词数(缝合的板子题)
代码:
import java.util.*;
import java.io.*;
public class Main {public static StringBuilder sk;public static String cs[];public static int s;public static boolean check(int x,int y) {String u=sk.substring(x,y+1);for(int i=1;i<=s;i++) {if(cs[i].length()>u.length()) continue;String tem=u.substring(0,cs[i].length());if(tem.equals(cs[i])) return true;}return false;}public static void main(String[] args)throws Exception{BufferedReader rd=new BufferedReader(new InputStreamReader(System.in));BufferedWriter wd=new BufferedWriter(new OutputStreamWriter(System.out));String dr[]=rd.readLine().split(" ");int n=Integer.parseInt(dr[0]),k=Integer.parseInt(dr[1]);sk=new StringBuilder(" ");for(int i=1;i<=n;i++) sk.append(rd.readLine());int len=n*20;boolean fal[]=new boolean [len+10];int dp[][]=new int [len+10][len+10];s=Integer.parseInt(rd.readLine());cs=new String [s+10];for(int i=1;i<=s;i++) cs[i]=rd.readLine();for(int i=len;i>=1;i--) {for(int j=i;j>=1;j--) {dp[j][i]=dp[j+1][i];if(check(j,i)) dp[j][i]++;}}int as[][]=new int [len+10][k+10];for(int i=0;i<len+10;i++) {Arrays.fill(as[i], -(int)1e9);}as[0][0]=0;for(int i=1;i<=len;i++) {for(int j=i;j>=1;j--) {for(int p=1;p<=k;p++) {as[i][p]=Math.max(as[i][p], as[j-1][p-1]+dp[j][i]);}}}System.out.print(as[len][k]+"\n");}}