codeforces 587B

题解:

我们考虑题目条件,相当于n个一段,连续k段中满足条件的子序列个数

枚举起始段是哪段,然后把n*k个数存下来,很容易DP

这个DP是dp[i]=∑(dp[j]) a[j]<=a[i],j在i的前一段

复杂度的话每段丢进树状数组,然后结束再删掉就好了

前面的重复段算一下有多少个,然后乘一下就好

但是这样会有点问题,就是到k段中包含最后一段(不满n个的那段)会需要每次都重新DP,这部分一共要O(k*n*k)的复杂度,不能接受

我们反着枚举

枚举结束段是哪段,然后同理DP,这边a[j]>=a[i]

结束段是最后一段时DP一次,是其他段时DP一次

但同样的问题,开头的段怎么办

开头部分直接利用其它段时DP的那次的结果,统计其中1~k-1段的答案即可(因为是整段,所以直接利用答案)

  1 #include<bits/stdc++.h>
  2 #define maxn 1000005
  3 #define ll long long
  4 using namespace std;
  5 const ll mod = 1000000007;
  6 ll n,k,l;
  7 ll a[maxn];
  8 ll m,p,q;
  9 ll b[maxn],d;
 10 ll c[maxn];
 11 ll f[maxn],g[maxn],ans;
 12 struct BIT
 13 {
 14     ll a[maxn];
 15     void clear()
 16     {
 17         memset(a,0,sizeof(a));
 18     }
 19     void add(int x,ll v)
 20     {
 21         for(;x<=maxn-5;x+=x&(-x))a[x]=(a[x]+v+mod)%mod; 
 22     }
 23     ll get(int x)
 24     {
 25         ll ans=0;
 26         for(;x;x-=x&(-x))ans=(ans+a[x])%mod;
 27         return ans;
 28     }
 29 }tr;
 30 int main()
 31 {
 32     scanf("%I64d%I64d%I64d",&n,&l,&k);
 33     for(int i=1;i<=n;++i)scanf("%d",&a[i]),b[i]=a[i];
 34     sort(b+1,b+n+1);
 35     d=unique(b+1,b+n+1)-b-1;
 36     for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+d+1,a[i])-b;
 37     m=l/n;p=l%n;
 38     if(!p)m--,p+=n;
 39     q=max(0ll,m-k+1);
 40     q%=mod;
 41     int cnt=0;
 42     for(int i=1;i<=k-1;++i)
 43         for(int j=1;j<=n;++j)c[++cnt]=a[j];
 44     for(int i=1;i<=p;++i)c[++cnt]=a[i];
 45     for(int i=cnt-p+1;i<=cnt;++i)f[i]=1,tr.add(c[i],f[i]);
 46     for(int i=k-1;i;--i)
 47     {
 48         for(int j=1;j<=n;++j)
 49         {
 50             int pos=(i-1)*n+j;
 51             f[pos]=(tr.get(maxn-5)-tr.get(c[pos]-1)+mod)%mod;
 52         }
 53         for(int j=1;j<=n;++j)
 54         {
 55             int pos=(i-1)*n+j;
 56             if(pos+n<=cnt)tr.add(c[pos+n],-f[pos+n]);
 57             tr.add(c[pos],f[pos]);
 58         }
 59     }
 60     for(int i=max(cnt-p-m*n+1,1ll);i<=cnt;++i)ans=(ans+f[i])%mod;
 61     memset(c,0,sizeof(c));
 62     tr.clear();
 63     cnt=0;
 64     for(int i=1;i<=k;++i)
 65         for(int j=1;j<=n;++j)c[++cnt]=a[j];
 66     for(int i=cnt-n+1;i<=cnt;++i)g[i]=1,tr.add(c[i],g[i]);
 67     for(int i=k-1;i;--i)
 68     {
 69         for(int j=1;j<=n;++j)
 70         {
 71             int pos=(i-1)*n+j;
 72             g[pos]=(tr.get(maxn-5)-tr.get(c[pos]-1)+mod)%mod;
 73         }
 74         for(int j=1;j<=n;++j)
 75         {
 76             int pos=(i-1)*n+j;
 77             tr.add(c[pos+n],-g[pos+n]);
 78             tr.add(c[pos],g[pos]);
 79         }
 80     }
 81     ll tmp=0;
 82     for(int i=1;i<=min(m,k-1);++i)
 83     {
 84         for(int j=1;j<=n;++j)
 85         {
 86             int pos=(k-i)*n+j;
 87             tmp=(tmp+g[pos])%mod;
 88         }
 89         ans=(ans+tmp)%mod;
 90     }
 91     tmp=0;
 92     for(int i=1;i<=k;++i)
 93         for(int j=1;j<=n;++j)
 94         {
 95             int pos=(i-1)*n+j;
 96             tmp=(tmp+g[pos])%mod;
 97         }
 98     tmp=tmp*q%mod;
 99     ans=(ans+tmp)%mod;
100     printf("%I64d\n",ans);
101     return 0;
102 }
View Code

猜你喜欢

转载自www.cnblogs.com/uuzlove/p/10547295.html