hdu 6078 Wavel Sequence(前缀和优化dp)

题目链接:hdu 6078 Wavel Sequence

题意:

给你a,b两个序列,让你在a,b中找出公共子序列p,满足p1<p2>p3<p4...,问有多少种方案。

题解:

考虑dp[i][j][2],表示a序列选择第i个数,b序列选择第j个数,该数和上一个数的关系是:0为小于,1为大于,的方案数。

那么

dp[i][j][0]=sum{ dp[k][l][1] | x<y,k<i,l<j} 其中x=a[i]=b[j],y=a[k]=a[j]。

dp[i][j][1]=sum{ dp[k][l][0] | x>y,k<i,l<j} 其中x=a[i]=b[j],y=a[k]=a[j]。


这样做显然是O(n4)的。考虑优化。

我们发现对于每一个i,j,都是找一个x从1到i-1,y从1到j-1的二维平面,将这个平面满足条件的值相加。

这里运用一个扫描线的思想,设dp[j][2],表示选择b序列的第j个数,后一维和上面一样。

for (i,1:n) for (j,1:m)。

对于i,表示当前已经考虑了a序列的前i个数了,对于j表示当前正在考虑b序列的第j个数。

那么我在for j的时候顺便把b[j]>x和b[j]<x的dp值累加起来。

当前考虑的是前i个数,那么显然当前的dp值的第一维下标都是小于i的,对于j,都是累加的小于j的下标dp值。

那么这个sum的值就是上面的sum{...}。

然后这样就可以O(n2)了。

 1 #include<cstdio>
 2 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 3 const int N=2007,P=998244353;
 4 int t,n,m,dp[N][2],a[N],b[N],ans;
 5 int main(){
 6     scanf("%d",&t);
 7     while(t--)
 8     {
 9         scanf("%d%d",&n,&m);
10         F(i,1,n)scanf("%d",a+i);
11         F(i,1,m)scanf("%d",b+i);
12         F(i,1,m)dp[i][0]=dp[i][1]=0;
13         int sum[2];ans=0;
14         F(i,1,n)
15         {
16             sum[0]=sum[1]=0;
17             F(j,1,m)
18             {
19                 if(a[i]==b[j])
20                 {
21                     dp[j][0]=(dp[j][0]+1)%P;
22                     dp[j][0]=(dp[j][0]+sum[1])%P;
23                     dp[j][1]=(dp[j][1]+sum[0])%P;
24                 }
25                 if(a[i]>b[j])sum[0]=(sum[0]+dp[j][0])%P;
26                 if(a[i]<b[j])sum[1]=(sum[1]+dp[j][1])%P;
27             }
28         }
29         F(i,1,m)ans=(1ll*ans+dp[i][0]+dp[i][1])%P;
30         printf("%d\n",ans);
31     }
32     return 0;
33 }
View Code

 

posted @ 2017-08-04 15:00  bin_gege  阅读(373)  评论(0编辑  收藏  举报