ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

1034 小魂和他的数列 dp 树状数组 最长的递增序列数

2022-08-13 15:31:40  阅读:136  来源: 互联网

标签:数列 int 小魂 1034 序列 长度 id dp


 链接:https://ac.nowcoder.com/acm/contest/26896/1034
来源:牛客网

题目描述

一天,小魂正和一个数列玩得不亦乐乎。
小魂的数列一共有n个元素,第i个数为Ai
他发现,这个数列的一些子序列中的元素是严格递增的。
他想知道,这个数列一共有多少个长度为K的子序列是严格递增的。
请你帮帮他,答案对998244353取模。 对于100%的数据,1≤ n ≤ 500,000,2≤ K ≤ 10,1≤ Ai ≤ 109

输入描述:

第一行包含两个整数n,K,表示数列元素的个数和子序列的长度。
第二行包含n个整数,表示小魂的数列。

输出描述:

一行一个整数,表示长度为K的严格递增子序列的个数对998244353取模的值。
示例1

输入

复制
5 3
2 3 3 5 1

输出

复制
2

说明

两个子序列分别是2 3 3 5 1和2 3 3 5 1。

分析

dp+树状数组

题目要求最长的递增序列。

很容易想到dp

设dp[i][j]为到 i 点,长度为 j 的序列

dp[i][j] = (a[k] < a[i]) * dp[k][j-1]

但是这种做法是n^3,1e5下明显tle

观察可以知道,如果先对原数列按照从小到大的顺序排序,

遍历到i,i前面的所有k的情况都已经处理好了,那就可以直接前缀和,但是由于坐标是乱的,所以要用树状数组处理到了当前 i 坐标,长度是j ,前面 [1,i] 有多少个坐标,长度是j - 1已经被选上了

有二维考虑二维树状数组。

同时,枚举到当前i ,长度是1的位置每次循环完 k 从K 到 2 ,都要 + 1

sum(i,j) 表示长度为j,在第i个位置前面有多少满足条件的情况,累加起来即可

这里要特殊判断一下,假如数组上有两个值是一样的,如果直接前缀和如果后面的数后放进来,会导致两个一样的数被累加,但这明显不满足a[k]<a[i]。

所以如果是一样的数,排序的时候先计算位置高的数,防止计算到它。

另外长度k 要从大到小计算,如果从小到大,在同一个i 位置会滚动加上对应位置和长度的值。

 

//-------------------------代码----------------------------

//#define int ll
const int N = 5e5+10,mod = 998244353;
int n,k;

struct node {
    int v,id;
    bool operator<(const node x) const {
        if(v == x.v) return id > x.id;//值相等,位置大的先?????????
        return v < x.v;
    }
} w[N];
int a[N][11];


//a[i][j] += (a[k] < a[i]) * a[k][j-1];
//只需要把第一个数到第i个数的所有满足情况的都加起来
void add(int i,int j,int x) {
    for(;i<=n;i+=lowbit(i)) {
        a[i][j] = (a[i][j] + x) % mod;//在a[i][j] 位置 加上权值
    }
}

int sum(int i,int j) {
    int res = 0;
    for(;i;i-=lowbit(i)) {
        res =(res + a[i][j]) % mod;
    } return res;
}

void solve()
{
//    cin>>n>>m;
    cin>>n>>k;
    fo(i,1,n) cin>>w[i].v,w[i].id = i;
    sort(w+1,w+1+n);
    fo(i,1,n) {
        of(j,k,2)
            add(w[i].id,j,sum(w[i].id,j-1));
        add(w[i].id,1,1);//递增序列为1的,肯定只产生一个贡献值
    }
    cout<<sum(n,k)<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

标签:数列,int,小魂,1034,序列,长度,id,dp
来源: https://www.cnblogs.com/er007/p/16583105.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有