原题链接:
HDU-6078
大意:
给出两个字符串
a[i]
,
b[i]
从中分别取数,组成
c[i]
,
c[i]
满足
c1<c2>c3<c4>c5......
波浪形。
求有多少种取法。
思路:
按照 dp 的思路,每次取第 i j 个数的时候至于前一个数有关,而且分为两种状态:这次取波谷或是取波峰.
即
fi,j,1=∑x=1i∑y=1jfx,y,0
fi,j,0=∑x=1i∑y=1jfx,y,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(n^4)的 ,利用滚动数组优化掉一维.
现在,考虑 dp[j][2]
循环 for(i 1 to n) for( j 1 to m) 的含义表示 在前 i 个 ai 范围内,考虑 bj 的情况。
利用 sum[0] 和 sum[1] 储存
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mem(s,t) memset(s,t,sizeof(s))
#define D(v) cout<<#v<<" "<<v<<endl
#define inf 0x3f3f3f3f
//#define LOCAL
inline void read(int &x){
x=0;char p=getchar();
while(!(p<='9'&&p>='0'))p=getchar();
while(p<='9'&&p>='0')x*=10,x+=p-48,p=getchar();
}
const int MAXN =2e3+10;
const int mod= 998244353;
int dp[MAXN][2],a[MAXN],b[MAXN],sum[2];
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t;
read(t);
while(t--){
int n,m;
read(n);read(m);
mem(a,0);mem(b,0);mem(dp,0);mem(sum,0);
for(int i=1;i<=n;i++){
read(a[i]);
}
for(int i=1;i<=m;i++){
read(b[i]);
}
for(int i=1;i<=n;i++){
sum[0]=sum[1]=0;
for(int j=1;j<=m;j++){
if(a[i]==b[j]){
dp[j][0]=(dp[j][0]+1)%mod;
dp[j][0]=(dp[j][0]+sum[1])%mod;
dp[j][1]=(dp[j][1]+sum[0])%mod;
}
if(a[i]>b[j]) sum[0]=(dp[j][0]+sum[0])%mod;
if(a[i]<b[j]) sum[1]=(dp[j][1]+sum[1])%mod;
}
}
ll ans=0;
for(int j=1;j<=m;j++){
ans=(ans+dp[j][0]+dp[j][1])%mod;
}
printf("%lld\n",ans);
}
return 0;
}
附:官方题解和标程
#include<cstdio>
const int N=2010,P=998244353;
int Case,n,m,i,j,k,t,a[N],b[N],g[N][N][2],h[N][N][2],ans;
inline void up(int&x,int y){x=x+y<P?x+y:x+y-P;}
int main(){
scanf("%d",&Case);
while(Case--){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=m;i++)scanf("%d",&b[i]);
for(i=1;i<=n;i++)for(j=1;j<=m;j++)for(k=0;k<2;k++)g[i][j][k]=h[i][j][k]=0;
for(ans=0,i=1;i<=n;i++)for(j=1;j<=m;j++)for(k=0;k<2;k++){
if(a[i]==b[j]){
t=h[i][j][k^1];
if(!k)up(t,1);
if(t){
up(ans,t);
up(g[i+1][j][k],t);
}
}
if(g[i][j][k]){
up(g[i+1][j][k],g[i][j][k]);
if(!k){if(a[i]>b[j])up(h[i][j+1][k],g[i][j][k]);}
else if(a[i]<b[j])up(h[i][j+1][k],g[i][j][k]);
}
if(h[i][j][k])up(h[i][j+1][k],h[i][j][k]);
}
printf("%d\n",ans);
}
return 0;
}