题目链接:https://www.luogu.com.cn/problem/P1026
感觉可以贪心,但是贪心只过了两个点╮(╯▽╰)╭
我的思路是这样的:我们从后往前去记录出现单词,数据量小完全可以暴力,然后将单词标记一下,首字母额外标记一下。
最后我们统计出有多少个单词,下面开始分割,如果没有被共用的字母大于k那么就输出ans,否则就从中减去。
——————————————————————————————————————————————————————————
在题解中终于翻到了一个和我思路很像的贪心做法。意料之中的是贪心的做法代码量确实少。这个题要dp就需要预处理一些东西
我贪心没有做好的一点就是被共用的字母我并没有去找一个最优解,这一部完全可以使用dp[i]来解决,从2-k直接贪心一下。每次找最少的切入点
——————————————————————————————————————————————————————————
再来看看dp做法,也是大部人的做法。 没有想到==
首先我们完全可以去处理每个分段的单词数量,这一步不难,然后预处理一下dp数组
在dp数组中,我们列举 结尾 段数 和至少开始的部分。
当前前i个字母中,分成j段。跟末尾字母后一项有关。l开头说明我们要用这个字母了,所以转移状态一定是上个分段+ (l+1,i)这一步已经预处理了;
dpcode:
#include<bits/stdc++.h> using namespace std; #define ll long long #define endl '\n' #define cyes cout<<"YES\n" #define cno cout<<"NO\n" #define mem(a) memset((a),0,sizeof (a)) inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} return x*f; } const int nn = 210; string s; string a[10]; int sum[nn][nn]; int dp[nn][50]; int n; int p,k; bool check(int l,int r){ string x = s.substr(l,r-l+1); for(int i=1;i<=n;i++) if(x.find(a[i])==0) return true; return false; } int main() { s+='0'; cin>>p>>k; string c; for(int i=1;i<=p;i++){ cin>>c; s+=c; } int m = s.size()-1; cin>>n; for(int i =1;i<=n;i++) cin>>a[i]; for(int i=m;i>=1;i--)//没什么好说的从位置从i - j的单词数 for(int j=i;j>=1;j--){ sum[j][i] = sum[j+1][i]; if(check(j,i)) sum[j][i]++; } dp[0][0] = 0; for(int i=1;i<=k;i++) dp[i][i] = dp[i-1][i-1] + sum[i][i]; for(int i=1;i<=m;i++) dp[i][1] = sum[1][i]; for(int i=1;i<=m;i++)//以i结尾 for(int j=1;j<=k&&j<i;j++)//分成j段的 for(int l=j;l<i;l++)//第j段至少从第j个位置开始 dp[i][j] = max(dp[i][j],dp[l][j-1]+sum[l+1][i]);//l用了就不能再用了 cout<<dp[m][k]<<endl; }
贪心code:
#include<stdio.h> #define min(a,b) ((a)<(b)?(a):(b)) #define LEN 20 char c[201] = {0}, word[6][200] = {0}; int d[41] = {0}, t[41] = {0}; int main() { int p, k, s, i, j, m, n, f, g, minum; scanf("%d%d", &p, &k); for(i = 0; i < p; i++) scanf("%s", c+i*LEN+1); scanf("%d", &s); for(i = 0; i < s; i++) scanf("%s", word[i]); for(i = 1; i <= p*LEN; i++) for(j = 0; j < s; j++) { for(m = 0; word[j][m] != 0; m++) if(word[j][m] != c[i+m]) break; if(word[j][m] == 0) { d[1]++; break; } } for(i = 2; i <= k; i++) { minum = 99999; for(j = 1; j <= p*LEN-1; j++) if(!t[j]) { f = 0; for(m = 0; m < s; m++) for(n = 0; word[m][n+1] != 0; n++) if(word[m][n] == c[j] && word[m][n+1] == c[j+1]) { f++; break; } if(minum > f) { minum = f; g = j; } } d[i] = d[i-1]-minum; t[g] = 1; } printf("%d\n", d[k]); return 0; }