CSU 1473 题解

转载请注明出处,http://blog.csdn.net/Bule_Zst/article/details/77119396


题目:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1473

Description

  给出一个包含N个各不相同的整数的序列,求其递增子序列的个数。

  输入的第一行为测试数据的组数T (T > 0)。
  
Input

  每组测试数的第一行为一个整数N (1 ≤ N ≤ 105 ),表示序列中一共有N个整数。接下来一行包含N个小于109的各不相同的非负整数,依次描述了这个序列中的各个整数。
  
Output

  对于每组测试数据,输出递增子序列的个数。由于结果可能会很大,所以只需要输出结果除以1000000007所得的余数即可。
  
Sample Input

2
3
1 2 3
4
3 1 4 2

Sample Output

7
7


方法:树状数组 详见 搞懂树状数组

用map记录数据的位置,根据数据的大小从小到大进行排序,然后依次传入函数,更新c数组。

c数组是用来求和a数组(a数组在代码中没有定义,存在在想象中)的,a[i]表示 对于原整数串,以第i位结尾的递增子序列的个数。

因为数据排过序,所以对于每次传入的 位置信息对应的数p 一定大于之前传入的,因此,对于传入的位置信息n,只需要求和a[1], a[2]…a[n-1](PS: 此时,比p大的数还未加入到a数组中),然后加到a[n]上,多加的1代表自身(一个数也认为是一个递增序列)。

// @Team    : nupt2017team12
// @Author  : Zst
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
#define LL long long
#define MOD 1000000007
#define CLR(a,x) memset(a,x,sizeof(a))
#define INF 0x3f3f3f3f
#define pb push_back
#define FOR(i,a,b) for( int i = ( a ); i <= ( b ); i++ )

const int N = 1e5+7;

int n;
int A[N];
int sorted[N];
map<int,int> Map;
int tree[N];

void add( int sub, int x )
{
    while( sub <= n ) {
        tree[sub] = ( tree[sub] + x ) % MOD;
        sub += ( sub & ( -sub ) );
    }
}

int sum( int x )
{
    int ans = 0;
    while( x > 0 ) {
        ans = ( ans + tree[x] ) % MOD;
        x -= ( x & ( -x ) );
    }
    return ans;
}


int main()
{
    // freopen( "H.txt", "r", stdin );
    int w;
    scanf( "%d", &w );
    while( w-- ) {
        CLR( tree, 0 );
        Map.clear();

        scanf( "%d", &n );
        FOR( i, 1, n ) {
            scanf( "%d", A + i );
            sorted[i] = A[i];
        }
        sort( sorted+1, sorted+n+1 );
        FOR( i, 1, n ) {
            Map[sorted[i]] = i;
        }

        FOR( i, 1, n ) {
            int rank = Map[A[i]];
            add( rank, sum( rank - 1 )+1 );
        }
        printf( "%d\n", sum( n ) );
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值