HDU 6078 Wavel Sequence (dp + 树状数组, 2017 Multi-Univ Training Contest 4)

29 篇文章 0 订阅
14 篇文章 0 订阅

Problem

含 N 个数的 a 数组 a1,a2,,an 和含 M 个数的 b 数组 b1,b2,,bm ,求有多少 a,b 公共子序列(记作 arr, 长为 len )满足 arr1<arr2>arr3<arr4>arr5

Limit

1N,M2000

1ai,bi2000

Idea

直接 dp 操作,记 dp[i][j][k] 表示公共子序列以 ai=bj 为结尾,同时为上述波浪序列的波峰/谷的方案数(k=0 表示波谷,k=1表示波峰)。

dp[i][j][k]=(dp[prei][prej][!k] | /) ,即使将 ai=bj 作为优化条件优化后也将达到 O(N4)

考虑通过二维树状数组优化求和,二维树状数组第一维表示枚举的 a 数组的第 i 个数,第二维表示 ai 的值(即 bj=ai 的值) 。

dp[i][j][0] = get(i-1, b[j]-1, 1)dp[i][j][1] = get(i-1, 2000, 0) - get(i-1, b[j], 0)get(x, y, wavel) 函数为获取二维树状数组所有在矩形 [1,1] -> [x, y] 的数值和(wavel 标识前置状态,由于波谷前必为波峰,波峰前必为波谷)。

若优先枚举 i 后枚举 j ,则可能存在查询树状数组时 arrp arrp+1 错位的情况,故应优先枚举 j ,后枚举 i 。

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 2000 + 10;
const int mod = 998244353;
int T, n, m, a[N], b[N], tree[N][N][2], dp[N][N][2];
int lowbit(int x) { return x & -x;  }
void add(int x, int y, int w, int wavel) {  //wavel = 0 means next a[i] > a[x] for i > x;
    for(int i=x;i<N;i+=lowbit(i))
    for(int j=y;j<N;j+=lowbit(j))
        (tree[i][j][wavel] += w) %= mod;
}
int get(int x, int y, int wavel) {
    int res = 0;
    for(int i=x;i;i-=lowbit(i))
    for(int j=y;j;j-=lowbit(j))
        (res += tree[i][j][wavel]) %= mod;
    return res;
}
int main()
{
    scanf("%d", &T);
    while(T--)
    {
        memset(tree, 0, sizeof(tree));
        memset(dp, 0, sizeof(dp));
        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]);
        long long ans = 0;
        for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++)
        {
            if(a[i] != b[j])    continue;
            (dp[i][j][0] = get(i-1, 2000, 1) - get(i-1, b[j], 1) + 1) %= mod;
            (ans += dp[i][j][0]) %= mod;
            (dp[i][j][1] = get(i-1, b[j]-1, 0)) %= mod;
            (ans += dp[i][j][1]) %= mod;

            add(i, b[j], dp[i][j][0], 0);
            add(i, b[j], dp[i][j][1], 1);
        }
        printf("%lld\n", (ans+mod) % mod);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值