强军如歌(strong)

强军如歌(strong)

题目描述

 

给定一个NN个数的序列AA,如果序列AA不是非降序的,你需要在其中选择一个数删掉,不断重复这个操作直到序列AA非降。求有多少种不同的删数方案。注意:删掉的数的集合相同,但是删数的顺序不同,视作不同的删数方案。

 

输入

 

第一行一个数NN。

接下来一行NN个正整数,用空格隔开,第ii个数表示Ai。

 

输出

 

一行一个整数表示答案对1000000007取模的结果。


solution

首先我们考虑不管删数顺序,枚举出剩下的不降序列。

假设长度为l

那么这时候的删数方案为(n-l)!

我们考虑一种不合法的删数方案:再删除第l个数前,序列一定要是不降的。

也就是每一个长度为l+1的不降序列,都对应着l+1个不合法方案。

用树状数组求出长度为l的不降子序列个数

这样就可以快速统计了

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 2005
#define mod 1000000007
#define ll long long
using namespace std;
int n,Max,a[maxn];
ll f[maxn][maxn],tree[maxn],ans[maxn],h[maxn];
int ask(int i){
    ll sum=0;
    for(;i;i-=i&-i)sum=(sum+tree[i])%mod;
    return sum;
}
void jia(int i,ll v){
    for(;i<=Max;i+=i&-i)tree[i]=(tree[i]+v)%mod;
}
int main()
{
    cin>>n;
    h[0]=1;for(int i=1;i<=n;i++)h[i]=(h[i-1]*i)%mod;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        Max=max(a[i],Max);
    }
    for(int i=1;i<=n;i++)f[i][1]=1;ans[1]=h[n];
    for(int i=2;i<=n;i++){
        for(int j=1;j<=Max;j++)tree[j]=0;
        for(int j=1;j<=n;j++){
            f[j][i]=ask(a[j]);
            jia(a[j],f[j][i-1]);
        }
        ll sum=0;
        for(int j=1;j<=n;j++)sum=(sum+f[j][i])%mod;
        ans[i]=(sum*h[n-i])%mod;
    }
    ll A=0;
    for(int i=1;i<=n;i++){
        A=A+ans[i]-(ans[i+1]*(i+1))%mod;A%=mod;
    }
    A=(A%mod+mod)%mod;
    cout<<A<<endl;
    return 0;
}

 

 

posted @   liankewei123456  阅读(222)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示