[博客迁移][题解] CSU 1473

228 阅读2分钟

from CSU 1473 题解


题目:acm.csu.edu.cn/csuoj/probl…

Description

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

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

  每组测试数的第一行为一个整数N (1 ≤ N ≤ 10^5),表示序列中一共有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;
}