链接:http://acm.hdu.edu.cn/showproblem.php?pid=6078
题意:找出两个序列中相同的子序列,且子序列满足a1<a2>a3<a4>a5……
思路:可以知道所谓子序列是从波谷开始的,当子序列只有一个元素时,他是自己的波谷,代码中我们可以用n^2的复杂度,对两个数列扫描,因为有这样一个性质,新扫到一个数字的话,如果这个数字在两个序列中都有,对于这两个相同数字之前的两个序列而言也是有可行解的,那这个相同数字是可以添加到可行解子串的后面变成波峰或者波谷;
例如:1 5 3和4 1 1 5 3
当a数列扫描到3的时候可知道之前是有可行解的两个(1,1)和两个(1,5 1,5)这个时候,(5,5)之所以是前面的解但是在此不能用的原因是因为子序列要从波谷开始,所以为了复杂度,这些东西要在扫的时候记录下来:
dp[0][j]是扫当前一轮,b数列的第j为波谷的情况,s[0][j]是扫到当前轮为止,b数列的第j为波谷的情况;
dp[1][j]是扫当前一轮,b数列的第j为波封的情况,s[1][j]是扫到当前轮为止,b数列的第j为波峰的情况;
中间的ans是暂存变量,虽然发现,只要a[i]和b[j]有大小关系的时候,ans就会加上s数组里面的数,但是发现,只有在相等的时候才会更新;这里不是很好理解,但是也是这个题的巧妙之处,我就假设我扫的当前a【i】在b中存在一个b【k】和它相等,所以,我扫描这个b【k】之前的元素时候,比较a【i】和b【j】大小的时候,就相当于比较b【j】和b【k】的大小,以此决定b【k】是否可以接在b【j】的后面成为新的可行解,而直到找到这个b【k】我才会更新值。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long LL; const LL mod=998244353; const int maxn=2005; int a[maxn],b[maxn]; LL dp[2][maxn],s[2][maxn]; int main() { freopen("input.txt","r",stdin); int t; scanf("%d",&t); while(t--) { memset(dp,0,sizeof dp); memset(s,0,sizeof s); int n,m; scanf("%d%d",&n,&m); for(int i=0;i<n;i++)scanf("%d",a+i); for(int i=0;i<m;i++)scanf("%d",b+i); LL sum=0; for(int i=0;i<n;i++) { LL ans0=1;//作为波谷的情况 LL ans1=0;//作为波峰的情况 for(int j=0;j<m;j++) { if(a[i]==b[j]) { dp[0][j]=ans0; dp[1][j]=ans1;//遇到相等就要更新 sum=(sum+ans1+ans0)%mod; } else if(a[i]>b[j]) { ans1+=s[0][j]%=mod; } else { ans0+=s[1][j]%=mod; } } for(int j=0;j<m;j++) { if(a[i]==b[j]) { s[0][j]+=dp[0][j]%=mod; s[1][j]+=dp[1][j]%=mod; } } } printf("%lld\n",sum); } return 0; }
时间: 2024-10-12 12:34:32