hdu 3030

这道题主要就是问你,长度为n的序列,有多少种上升的子序列

当前点的情况种数等于前面所有小于它的点的种数相加 + 1

1就是只有这一个点的时候的序列

那就是要多次查询前面比它小的点的种数的和

那么就是区间求和

用到树状数组就过了

一开始我用的a[k]表示这个点的值等于k时有多少种情况,但是后来考虑到对

输入的值没有限制

有可能这个点的值等于 100000000

那我就要建这么大的数组 明显过不去

并且我们只要直到这个点前面的种数和就行  

排序后查找就行了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5e5+5;
long long b[maxn];
long long a[maxn];
long long val[maxn];
long long n;
long long mod = 1e9+7;
long long getsum(long long c[],long long i);
long long lowbit(long long k);
void add(long long c[],long long i,long long j);
int main()
{
    int t;
    scanf("%d",&t);
    for(int ll = 1; ll <= t; ++ll)
    {
        long long m,x,y,z;
        scanf("%lld%lld%lld%lld%lld",&n,&m,&x,&y,&z);
        for (long long i = 0; i < m; i++)
            scanf("%lld",&a[i]);
        for (int i = 0; i < n; i++){
            b[i+1] = val[i+1] = a[i%m];
            a[i%m] = (x*a[i%m]+y*(i+1))%z;
        }
        memset(a, 0,sizeof(a));
        sort(b+1,b+n+1);
        long long sum = 0;
        for(long long i=1;i<=n;++i)
        {
            long long pos = lower_bound(b+1,b+n+1,val[i]) - b;
            long long ans = getsum(a, pos-1) + 1;
            sum += ans;
            sum %= mod;
            add(a,pos,ans);
        }
        printf("Case #%d: %lld\n",ll,sum);
    }
}
long long lowbit(long long k)
{
    return k&(-k);
}
void add(long long c[],long long i,long long j)
{
    while(i<=n)
    {
        c[i] += j;
        c[i] %= mod;
        i += lowbit(i);
    }
}
long long getsum(long long c[],long long i)
{
    long long sum = 0;
    while(i > 0)
    {
        sum += c[i];
        sum %= mod;
        i -= lowbit(i);
    }
    return sum;
}

猜你喜欢

转载自www.cnblogs.com/mltang/p/8948291.html