bzoj4798[CEOI2015] Calvinball championship

这年头,n方跑1万的题已经不多了...

题意

bzoj4798
不知道怎么叙述这个题意...

分析

如果某个序列字典序小于给定的序列,我们不妨考虑从左到右第一个小于给定的序列的位置,并枚举这个位置的数值.这个位置及之前的分组方案可以由此确定.之后每多一位置,可能是和之前的某个位置分到同一组,也可能是新建立一组.定义f[i][j]表示当前分了i组,还需要在后面添加j个位置的方案数.那么f[i][j]=f[i+1][j-1]+f[i][j-1]*i.需要滚动数组.(需要滚掉的是j那一维)
如果感觉我口胡得不明白可以查CEOI官网的题解...

#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=1000007;
const int maxn=10005;
int a[maxn];
int Max[maxn];
int f[2][maxn];
int main(){
  int n;scanf("%d",&n);
  for(int i=1;i<=n;++i){
    scanf("%d",a+i);
  }
  for(int i=1;i<=n;++i)Max[i]=max(Max[i-1],a[i]);
  for(int i=1;i<=n;++i)f[0][i]=1;
  int ans=0;
  int flag=0;
  for(int i=n;i>=2;--i){
    flag^=1;
    for(int j=1;j<=n;++j){
      f[flag][j]=(f[flag^1][j+1]+f[flag^1][j]*1ll*j)%mod;
    }
    for(int j=1;j<a[i];++j)
      ans=(ans+f[flag^1][Max[i-1]])%mod;
  }
  printf("%d\n",(ans+1)%mod);
  return 0;
}

posted @ 2017-06-14 14:07  liu_runda  阅读(228)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难