码迷,mamicode.com
首页 > 其他好文 > 详细

赤壁之战

时间:2020-04-11 23:39:27      阅读:94      评论:0      收藏:0      [点我收藏+]

标签:const   for   复杂度   范围   个数   bit   mod   content   class   

题目连接:

https://www.acwing.com/problem/content/299/

Description

给定一个长度为N的序列A,求A有多少个长度为M的严格递增子序列。

Input

第一行包含整数T,表示共有T组测试数据。

每组数据,第一行包含两个整数N和M。

第二行包含N个整数,表示完整的序列A。

Output

每组数据输出一个结果,每个结果占一行。

输出格式为“Case #x: y”,x为数据组别序号,从1开始,y为结果。

由于数据可能很大,请你输入对\(10^9+7\)取模后的结果。

Sample Input

2
3 2
1 2 3
3 2
3 2 1

Sample Output

Case #1: 3
Case #2: 0

Hint

数据范围
\(1≤T≤100, 1≤M≤N≤1000, N×M的和小于10^7\)
序列中的整数的绝对值不超过\(10^9\)

题意

在长度为n的序列中求长度为m的严格递增子序列的个数

题解:

首先考虑二维DP,f[i][j]表示前i个且第i个作为最后一个数的长度为j的严格递增子序列个数,f[i][j]+=f[k][j-1](k<i & a[k]<a[i]) DP可以写成

for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
        for(int k=1;k<i;++k)
            f[i][j]+=f[k][j-1]

复杂度O(1e10)了,我们需要降掉一维,或者变成n变logn的复杂度。
第三层循环我们需要找到k<i且a[k]<a[i]的所有f[k][j]的和,即在a[i]之前的和,这样很容易想到用树状数组点插入的做法了,在算第j维时,求j-1维在树状数组中a[i]点之前的前缀和,可以维护一个m维的树状数组。实际上,我们每次只需要j的上一维的树状数组,把第一第二层循环交换一下,就只用维护一个一维的树状数组,每次用完清空,也只用一维的f[i]记录上一维的f[i][j-1]。先更新j-1维的f[i]更新到a[i],再用f[i]的存a[i]-1之前的f[k][j-1]的和即得f[i][j]。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1010,mod=1e9+7;
int f[N],tr[N],a[N],b[N];
inline int lowbit(int x) {
    return x&(-x);
}
void add(int x,int y){
    while(x<N){
        (tr[x]+=y)%=mod;
        x+=lowbit(x);
    }
}
int sum(int x){
    int res=0;
    while(x>0){
        (res+=tr[x])%=mod;
        x-=lowbit(x);
    }
    return res;
}
int main(){
    int T;
    cin>>T;
    for(int cas=1;cas<=T;++cas){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;++i){
            cin>>a[i];
            b[i]=a[i];
        }
        sort(b+1,b+1+n);
        int tot=unique(b+1,b+1+n)-b;
        for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
        for(int i=1;i<=n;++i) f[i]=1;
        for(int i=2;i<=m;++i){
            for(int j=1;j<=tot;++j) tr[j]=0;
            for(int j=1;j<=n;++j){
                add(a[j],f[j]);
                f[j]=sum(a[j]-1);
            }
        }
        int res=0;
        for(int i=1;i<=n;++i) (res+=f[i])%=mod;
        cout<<"Case #"<<cas<<": "<<res<<endl;
    }
    return 0;
}

赤壁之战

标签:const   for   复杂度   范围   个数   bit   mod   content   class   

原文地址:https://www.cnblogs.com/jjl0229/p/12682857.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!