zoukankan      html  css  js  c++  java
  • hdu6078 Wavel Sequence dp+二维树状数组

    //#pragma comment(linker, "/STACK:102400000,102400000")
    
    
    /**
    题目:hdu6078 Wavel Sequence
    链接:http://acm.hdu.edu.cn/showproblem.php?pid=6078
    题意:给定a序列和b序列。从a中取一个子序列x(数的位置顺序保持不变),子序列每个数满足a1<a2>a3<a4>a5<a6...  波浪形
    从b中取相同长度的子序列y,也满足波浪形。 如果x与y序列一模一样,那么找到一个匹配方式。
    求a与b两个序列有多少种匹配方式(相同的数但不同的位置,那么算作不同)。
    
    思路:
    定义dp[i][j][k]表示x序列以a[i]为结尾,y序列以b[j]结尾,k=0表示a[i]是波谷,k=1表示a[i]是波峰时候的匹配方式。
    容易想到
    dp[i][j][0] = sigma(dp[x][y][1]), x<i,y<j,b[x]>b[i];    (a[i]==b[j],a[x]==b[y])
    dp[i][j][1] = sigma(dp[x][y][0]), x<i,y<j,b[x]<b[i];
    由于i的枚举是最外围循环,所以当前这个i要得到的结果来源前面计算过的,一定满足x<i.所以x<i不用作为限制因素。
    现在要考虑满足y<j,b[x]>b[i]||b[x]<b[i]; 所以用二维树状数组维护y和b[x]。
    
    定义c[j][value][k]表示y序列的结尾下标在j以内,数值大小value以内,波浪状态为k时候的匹配方式数。
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<vector>
    #include<queue>
    #include<set>
    #include<cstring>
    #include<time.h>
    #include<random>
    #include<cmath>
    using namespace std;
    typedef pair<int,int> P;
    typedef long long LL;
    const int mod = 998244353;
    const int INF = 0x3f3f3f3f;
    const int N = 2005;
    int n, m;
    int a[N], b[N];
    int dp[N][2];
    int c[N][N][2];
    ///二维树状数组
    int query(int i,int j,int flag)
    {
        int s = 0;
        for(int x = i; x > 0; x-=(x&(-x))){
            for(int y = j; y > 0; y-=(y&(-y))){
                s = (s+c[x][y][flag])%mod;
            }
        }
        return s;
    }
    void update(int i,int j,int flag,int d)
    {
        for(int x = i; x <= 2000; x+=(x&(-x))){
            for(int y = j; y <= 2000; y+=(y&(-y))){
                c[x][y][flag] = (c[x][y][flag]+d)%mod;
            }
        }
    }
    int main()
    {
        int T;
        cin>>T;
        for(int i = 0; i<T; i++)
        {
            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]);
            memset(c, 0, sizeof c);
            LL ans = 0;
            for(int i = 1; i <= n; i++){
                for(int j = 1; j <= m; j++){
                    if(a[i]!=b[j]) continue;
                    dp[j][0] = (query(j,2000,1)-query(j,b[j],1)+1+mod)%mod;///+1是因为每一个b[j]都可以单独自身作为波谷,成为一个序列。
                    dp[j][1] = query(j,b[j]-1,0);
                    ans = (ans+dp[j][0]) %mod;
                    ans = (ans+dp[j][1]) %mod;
                    update(j,b[j],0,dp[j][0]);
                    update(j,b[j],1,dp[j][1]);
                }
            }
            printf("%lld
    ",ans);
    
        }
        return 0;
    }
  • 相关阅读:
    nignx简单操作
    nginx的原理
    nginx简单了解
    操作数栈
    静态变量与局部变量
    遇到C语言内存错误怎么办?一定要找准这六个原因
    千万不要以为程序员是靠技术生存!六句话改变你对程序员的认知
    关于C语言Switch语句,先学这些技巧够不够?
    作为一个码农的悲哀:我是架构师,而你不是
    引用不如指针强大?C++引用,为你深度解析
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7295891.html
Copyright © 2011-2022 走看看