• 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
    ",ans);
    101     return 0;
    102 }
    View Code
  • 相关阅读:
    今日头条Go建千亿级微服务的实践
    Apache JServ Protocol
    tomcat servlet JSP common gateway interface 公共网关接口
    pollable event-driven Flume source
    kernel.panic
    Linux查找含有某字符串的所有文件
    深入理解Linux修改hostname
    px em rem
    这跟他们的前辈在原生应用程序或印刷出版物中做的设计或多或少有点类似。
    字符串等长切分 视频字幕换行
  • 原文地址:https://www.cnblogs.com/uuzlove/p/10547295.html
Copyright © 2020-2023  润新知