有点动态规划的意思。
假设Eva最喜欢的颜色分别为favor[0]、favor[1]、favor[2]……favor[m-1],而给定的序列为shu[0]、shu[1]、shu[2]……shu[n-1]。(题目里说颜色有n种,那个n没用的,所以我还是习惯性地在代码里把序列长度叫做n)
我们可以先有这样一个大体的思路:“根据后面的,往前面推算”,在给定序列的第i位,也就是shu[i],如果我们已经知道序列的(i+1)——(n-1)最长可以凑出长为len的串,那我们只需要判断一下shu[i]本身,如果shu[i]能放在那个长为len的串前面,那么序列的i——(n-1)位最长能凑出len+1串;否则,序列的i——(n-1)位最长只能凑出长为len的串。
所以,整个过程是从后往前处理的,最后我们会得出序列的第0——(n-1)位最长能凑出多长的串,也就是题目的答案了。
现在要考虑的是,怎么判断shu[i]本身呢?怎么知道它能不能放在已有串的前面呢?何况“已有最长串”也不是唯一的呀。
解决方法是,把这种“从后往前”的处理操作m次,每次“从后往前”都是针对具体的一种颜色来的,第一次,遍历的时候要判断每个shu[i]是否等于favor[m-1],是的话说明串串可以加一了,这样按前面讲的思路,这一遍下来,我们就知道i——(n-1)位 能凑出的、仅含favor[m-1]的最大串长是多少(i=0,1,2……(n-1))。
第二遍,遍历的时候判断shu[i]是否等于favor[m-2],是的话可以加一,因为,显然,已有的串是 只含favor[m-1] 或 只含favor[m-1]和favor[m-2]两种颜色的,所以加一不会有颜色顺序不对的问题。所以尽管解有可能不唯一,我们还是只需计算、保存这个长度即可,这个长度一定是正确的。
第三遍……第四遍……第m遍。输出最终结果。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int kind;
int favor[205],m;
int shu[10005],n;
int most[10005];
int main(){
int i;
scanf("%d",&kind);
scanf("%d",&m);
for(i=0;i<m;i++){
scanf("%d",&favor[i]);
}
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&shu[i]);
memset(most,0,sizeof(most));
int j;
for(j=m-1;j>=0;j--){
for(i=n-1;i>=0;i--){
if(shu[i]==favor[j]){
if(most[i+1]+1>most[i])
most[i]=most[i+1]+1;
}
else{
if(most[i+1]>most[i])
most[i]=most[i+1];
}
}
}
printf("%d\n",most[0]);
return 0;
}