zoukankan      html  css  js  c++  java
  • bzoj4361 isn

    Description

    给出一个长度为n的序列A(A1,A2...AN)。如果序列A不是非降的,你必须从中删去一个数,
    这一操作,直到A非降为止。求有多少种不同的操作方案,答案模10^9+7。

    Input

    第一行一个整数n。
    接下来一行n个整数,描述A。

    Output

    一行一个整数,描述答案。

    Sample Input

    4
    1 7 5 3

    Sample Output

    18

    HINT

    1<=N<=2000

    正解:$dp$+树状数组。

    感觉自己有点智商掉线,挺简单的一道题竟然没想出来。。

    首先我们把所有方案数按照最后剩下的序列长度分类。

    那么$ans=sum_{i=1}^{n}f[i]*(n-i)!$,其中$f[i]$为长度为$i$的不降序列个数。

    我们发现这样会算重,然后可以注意到算重的充要条件就是当这个序列的长度为$i+1$时就已经不降了。

    所以再减去$f[i+1]*(i+1)*(n-i-1)!$即可。求$f$用一个简单的树状数组优化$dp$就行了。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define rhl (1000000007)
     6 #define lb(x) (x & -x)
     7 #define N (2005)
     8 
     9 using namespace std;
    10 
    11 int c[N][N],a[N],f[N],fac[N],hsh[N],n,tot,ans;
    12 
    13 il int gi(){
    14   RG int x=0,q=1; RG char ch=getchar();
    15   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    16   if (ch=='-') q=-1,ch=getchar();
    17   while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    18   return q*x;
    19 }
    20 
    21 il void add(RG int op,RG int x,RG int v){
    22   for (;x<=tot;x+=lb(x)){
    23     c[op][x]+=v; if (c[op][x]>=rhl) c[op][x]-=rhl;
    24   }
    25   return;
    26 }
    27 
    28 il int query(RG int op,RG int x){
    29   RG int res=0;
    30   for (;x;x^=lb(x)){
    31     res+=c[op][x]; if (res>=rhl) res-=rhl;
    32   }
    33   return res;
    34 }
    35 
    36 int main(){
    37 #ifndef ONLINE_JUDGE
    38   freopen("isn.in","r",stdin);
    39   freopen("isn.out","w",stdout);
    40 #endif
    41   n=gi(),fac[0]=1;
    42   for (RG int i=1;i<=n;++i)
    43     hsh[i]=a[i]=gi(),fac[i]=1LL*fac[i-1]*i%rhl;
    44   sort(hsh+1,hsh+n+1),tot=unique(hsh+1,hsh+n+1)-hsh-1;
    45   for (RG int i=1;i<=n;++i){
    46     a[i]=lower_bound(hsh+1,hsh+tot+1,a[i])-hsh;
    47     for (RG int j=i,tmp;j;--j){
    48       tmp=j==1?1:query(j-1,a[i]),add(j,a[i],tmp);
    49       f[j]+=tmp; if (f[j]>=rhl) f[j]-=rhl;
    50     }
    51   }
    52   for (RG int i=1;i<=n;++i){
    53     ans=(1LL*fac[n-i]*f[i]+ans)%rhl;
    54     if (i<n) ans=(ans-1LL*fac[n-i-1]*f[i+1]%rhl*(i+1))%rhl;
    55   }
    56   cout<<(ans+rhl)%rhl; return 0;
    57 }
  • 相关阅读:
    四则运算网页版
    第六周工作日志
    课堂作业数组最大和
    第五周总结
    四则运算三结对开发
    学习进度第四周
    个人模块记录表
    学习进度表第三周
    四则运算第二篇
    保序回归问题
  • 原文地址:https://www.cnblogs.com/wfj2048/p/8455412.html
Copyright © 2011-2022 走看看