hdu6078 Wavel Sequence 2017多校第四场1012 dp

来源:互联网 发布:linux中echo命令详解 编辑:程序博客网 时间:2024/06/07 05:38

http://acm.hdu.edu.cn/showproblem.php?pid=6078

题意:给定数组a和b,在a和b中取几个数,使满足a[i]=b[j],且a[1]<a[2]>a[3]<a[4]>a[5]...。求这样的子序列有多少。

题解:

dp[i][j][0]:a数组前i个与b数组前j个满足题意的所有方案数,且a[i]=b[j]为波谷。

dp[i][j][1]:a数组前i个与b数组前j个满足题意的所有方案数,且a[i]=b[j]为波峰。

up:当a[i]>b[j],这个时候a[i]可以作为波峰的所有情况数,就是up+=dp[i-1][j][0](b[j]作为波谷)。

down:当a[i]<b[j],这个时候a[i]可以作为波峰的所有情况数,就是down+=dp[i-1][j][1](b[j]作为波峰)。

发现,只有a[i]==a[j]时,才对答案有贡献。

那么状态转移方程就是:

dp[i][j][0]=dp[i-1][j][0]+down(满足a[i]==b[j],a[i]作为波谷的所有方案数)

dp[i][j][1]=dp[i-1][j][1]+up    (满足a[i]==b[j],a[i]作为波峰的所有方案数)

然后可以用滚动数组压倒二维。

代码:

#include<bits/stdc++.h>#define debug cout<<"aaa"<<endl#define d(a) cout<<a<<endl#define mem(a,b) memset(a,b,sizeof(a))#define LL long long#define lson l,mid,root<<1#define rson mid+1,r,root<<1|1#define MIN_INT (-2147483647-1)#define MAX_INT 2147483647#define MAX_LL 9223372036854775807i64#define MIN_LL (-9223372036854775807i64-1)using namespace std;const int N = 2000 + 5;const int mod = 998244353;const double eps = 1e-8;int up,down,t,n,m;int dp[N][2],a[N],b[N];LL ans;int main(){scanf("%d",&t);while(t--){ans=0,mem(dp,0);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=m;i++){scanf("%d",&b[i]);}for(int i=1;i<=n;i++){up=down=0;for(int j=1;j<=m;j++){if(a[i]==b[j]){//这个+1算是dp开始的初始化,因为题目要求第一个是波谷 (dp[j][0]+=1)%mod;//a[i]为波谷 (dp[j][0]+=down)%=mod;//a[i]为波峰 (dp[j][1]+=up)%=mod;}else if(a[i]<b[j]){//这个时候,a[i]可以作为波谷,b[j](就是a[j]。。)为波峰,这两个波峰波谷相邻。 (down+=dp[j][1])%=mod;}else{//这个时候,a[i]可以作为波峰,b[j]为波谷,这两个波峰波谷相邻。 (up+=dp[j][0])%=mod;}}}//计算总方案数 for(int i=1;i<=m;i++){(ans+=dp[i][0]+dp[i][1])%=mod;}printf("%lld\n",ans);}return 0;}