2/10 P1026 统计单词(跟昨天的P1018乘积最大差不多)
说是差不多啦,但还是不看题解不会做www
思路一样,只是乘积最大那道题里,分割点是m,这道题里段数是m,所以循环条件和初始化有些不一样
先看转移方程:
dp [ i ][ j ] = max ( dp [ i ] [ j ] , dp [ m ] [ j - 1 ] + have [ m + 1 ] [ i ] )
因为 m 代表的是段数,如果 m = i 的话,m+1 就会超过 i ,所以 m<=i-1
那不是还有 i 个字母全部都自成一段的情况会漏掉吗?
那就提前解决这种特殊情况
dp[i][i]=dp[i-1][i-1]+have[i][i]____i<=k!,最多分k段!
然后是怎么找每段里有多少个单词:
我们是用 string 的 find 来找的,返回的是第一个找到的引索,所以如果从前往后找的话,会一直返回第一个,找不到后面的,所以要从后往前找
然后是前后边界 l 和 r ,当 l 往左移动一次,那么当前状态的总数自然要加上(l+1,r),如果新区间内 存在一个单词的引索为 0,那么就 +1
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
int p,k,word,dp[220][50],have[220][220],len;
string s,t,dic[8];
bool ck(int l,int r){
string a;
a=s.substr(l,r-l+1);
for(int i=1;i<=word;i++){
if(a.find(dic[i])==0) return true;
}
return false;
}
int main()
{
cin>>p>>k;
s+='0';
for(int i=1;i<=p;i++)
{
cin>>t;
s+=t;
}
cin>>word;
for(int i=1;i<=word;i++)
{
cin>>dic[i];
}
len=s.length()-1;
for(int i=len;i>=1;i--)
{
for(int j=i;j>=1;j--)
{
have[j][i]=have[j+1][i];
if(ck(j,i))
{
have[j][i]++;
}
}
}
for(int i=1;i<=k;i++)
{
dp[i][i]=dp[i-1][i-1]+have[i][i];
}
for(int i=1;i<=len;i++)
{
dp[i][1]=have[1][i];
}
for(int i=2;i<=len;i++)
{
for(int j=1;j<=min(i-1,k);j++)
{
for(int m=j;m<i;m++)
{
dp[i][j]=max(dp[i][j],dp[m][j-1]+have[m+1][i]);
}
}
}
cout<<dp[len][k];
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架