hdu6078

多校第四場1012

Wavel Sequence
題意是定義一種波浪數列,滿足a1< a2 > a3 < a4 > a5
給兩個數列a,b,選出a b的一個公共子串,且是一個波浪數列,問這樣的方案有多少種。
這個題相當於公共子序列裏再套一個dp
定義dp[i][j][k]爲a串前i個且以b串j結尾且上升狀態爲k時的方案數,那麼就可以枚舉轉移了。

     dp[i][j][0] += dp[i-1][j][0] ;
     dp[i][j][1] += dp[i-1][j][1] ;
    if(a[i]== b[j]
    {   
     dp[i][j][0] += dp[i-1][k][1](0<=k<j && b[k] < b[j])
     dp[i][j][1] += dp[i-1][k][0] (0<=k < j &&b[k] > b[j] )
    }

這樣子基本上就算是轉移完了這個方程。
但是!!!!!!!!最最最重要的是,這裏存在了一個k需要枚舉,也就是說這個dp是三維的,串長的2000,三維顯然不現實。現場做的時候完全束手無策。
很絕望,因爲感覺真的很菜,賽後看題解也看不懂,最後看別人博客的時候恍然大悟。其實非常好解決,注意到需要枚舉的情況是當a[i] == b[j]的時候,那麼在這種情況下,在外層循環枚舉i的時候,把所有b[j]< a[i]和b[j] > a[i]的方案都和起來,然後轉移的時候就不用一個個的去枚舉了。很輕鬆地就把方程從三維降到了二維。
這種細節真的很重要,以後在dp的時候要注重這些可以優化的細節。

#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<iostream>
#include<stdlib.h>
using namespace std;
#define  LONG long long
const LONG  INF=0x3f3f3f3f;
const LONG  MOD=998244353;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson  l , mid , rt<< 1
#define rson  mid + 1 ,r , (rt<<1)+1
#define root 1, n , 1
LONG dp[2105][2105][2] ;
LONG a[2105];
LONG b[2105] ;
LONG Sum[2105][2] ;
int main()
{
    int T;
    cin >> T;
    while( T -- )
    {
        int  n, m ;
        clr0(dp ) ;
        cin >> n>> m ;
        for(int i = 1 ;i<= n ; ++ i)
            cin >> a[i] ;
        for(int j = 1; j<= m ;++ j)
            cin >>b[j] ;
        for(int i = 0 ;i <= n + 10 ; ++ i)
             dp[i][0][0] = 1;
        for(int i = 1;i <= n ; ++ i)
        {
            clr0(Sum) ;
            LONG Sum0 =1 ;
            LONG Sum1 = 0;
            for(int j = 1;j <= m ; ++j)
            {
                if(a[i] == b[j])
                {
                    dp[i][j][0] += dp[i-1][j][0] ;
                    dp[i][j][1] += dp[i-1][j][1];
                    ( dp[i][j][0] += Sum1 ) %= MOD ;
                    ( dp[i][j][1] += Sum0 ) %= MOD ;
                }
                else
                {
                        ( dp[i][j][0] += dp[i-1][j][0] ) %= MOD ;
                        ( dp[i][j][1] += dp[i-1][j][1] ) %= MOD ;
                }
                if( b[j] < a[i] )
                    ( Sum1 += dp[i][j][1] ) %= MOD ;
                if( b[j] > a[i])
                    ( Sum0 += dp[i][j][0] ) %= MOD ;
            }

        }
        LONG ans = 0 ;
        for(int i = 1;i <= m ; ++i) ans += dp[n][i][0] +dp[n][i][1] ,ans %= MOD ;
        cout<<ans<<endl;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章