zoukankan      html  css  js  c++  java
  • [atARC100F]Colorful Sequences

    考虑求任意序列中$a$出现次数之和减去不合法序列中$a$出现次数之和,前者即为$(n-m+1)k^{n-m}$(一个序列重复次数恰好为$a$出现次数),对于后者,先忽略$a$的次数,即统计有多少个不合法序列

    考虑dp,令$f[i][j]$表示前$i$个数,后$j$个数各不相同(且后$j+1$个数存在相同)的不合法序列数,转移对最后一个数分类讨论:

    1.与第$i-j$个数不同,即长度增加1,则有$f[i][j]+=(k-(j-1))f[i-1][j-1]$

    2.与第$i-j$个数相同,那么上一次长度任意,即$f[i][j]+=sum_{t=j}^{k}f[i-1][t]$

    暴力时间复杂度为$o(nk^{2})$,前缀和优化可以做到$o(nk)$,再考虑$a$的影响,对$a$分类讨论:

    1.若$a$中包含一个$k$阶排列($a$合法),那么存在$a$必然合法,即不合法序列中$a$出现次数之和为0

    2.若$a$中元素各不相同且$m<k$,定义$g[i][j]$表示所有$f[i][j]$序列中长为$m$且各不相同的子串数之和,转移类似,即在$jge m$时累计入$g[i][j]$中即可

    同时,由于$m$个元素以及顺序已经确定,因此要除以$P(k,m)$(其中$P$为排列,即$P(n,m)=frac{n!}{(n-m)!}$)

    3.若$a$中包含相同的元素,令$x$为最大的$x$满足$[1,x]$中元素各不相同,$y$为最小的$y$使得$[y,m]$中元素各不相同,将整个序列分为$[1,x]$、$(x,y)$和$[y,m]$三部分

    若$(x,y)$非空,那么即要求$(x,y)$不会影响其合法性,考虑如果存在一段长度为$k$的排列经过这个,那么必然不能完全在$[1,m]$内部(第一种情况),那么如果选择左边"出去",则不能选择到$x+1$,右边同理,即得证

    具体来说,先枚举出现$a$的位置$i$,再枚举最后一段,即$sum_{i=1}^{n}frac{sum_{j=x}^{k-1}f[i+x-1][j]}{P(k,x)}cdot frac{sum_{j=m-y+1}^{k-1}f[n-(i-1)-(y-1)][j]}{P(k,m-y+1)}$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 25005
     4 #define K 405
     5 #define mod 1000000007
     6 int n,m,k,ans,inv[K],a[N],vis[N],las[K],f[N][K],g[N][K];
     7 int p_inv(int n,int m){
     8     int ans=1;
     9     for(int i=n-m+1;i<=n;i++)ans=1LL*ans*inv[i]%mod;
    10     return ans;
    11 }
    12 int main(){
    13     inv[0]=inv[1]=1;
    14     for(int i=2;i<K-4;i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
    15     scanf("%d%d%d",&n,&k,&m);
    16     for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    17     ans=n-m+1;
    18     for(int i=1;i<=n-m;i++)ans=1LL*ans*k%mod;
    19     int tot=0,flag=0,x,y;
    20     for(int i=1;i<=m;i++){
    21         if (++vis[a[i]]==1)tot++;
    22         if ((i>k)&&(--vis[a[i-k]]==0))tot--;
    23         if (tot==k){
    24             printf("%d",ans);
    25             return 0;
    26         }
    27     }
    28     f[0][0]=1;
    29     for(int i=1;i<=n;i++){
    30         tot=0;
    31         for(int j=k-1;j;j--){
    32             tot=(tot+f[i-1][j])%mod;
    33             f[i][j]=(1LL*(k-j+1)*f[i-1][j-1]+tot)%mod;
    34         }
    35     }
    36     for(int i=1;i<=m;i++)las[a[i]]=i;
    37     for(int i=1;i<=m;i++)
    38         if (las[a[i]]!=i)flag=1;
    39     if (!flag){
    40         for(int i=1;i<=n;i++){
    41             tot=0;
    42             for(int j=k-1;j;j--){
    43                 tot=(tot+g[i-1][j])%mod;
    44                 g[i][j]=(1LL*(k-j+1)*g[i-1][j-1]+tot)%mod;
    45                 if (j>=m)g[i][j]=(g[i][j]+f[i][j])%mod;
    46             }
    47         }
    48         tot=0;
    49         for(int i=1;i<=k;i++)tot=(tot+g[n][i])%mod;
    50         printf("%d",(ans+mod-1LL*tot*p_inv(k,m)%mod)%mod);
    51         return 0;
    52     }
    53     memset(las,0,sizeof(las));
    54     for(int i=1;i<=m;i++){
    55         if (las[a[i]]){
    56             x=i-1;
    57             break;
    58         }
    59         las[a[i]]=1;
    60     }
    61     memset(las,0,sizeof(las));
    62     for(int i=m;i;i--){
    63         if (las[a[i]]){
    64             y=i+1;
    65             break;
    66         }
    67         las[a[i]]=1;
    68     }
    69     for(int i=1;(i+x-1<=n)&&(i-1<=n-(y-1));i++){
    70         int s1=0,s2=0;
    71         for(int j=x;j<k;j++)s1=(s1+f[i+x-1][j])%mod;
    72         for(int j=m-y+1;j<k;j++)s2=(s2+f[n-(i-1)-(y-1)][j])%mod;
    73         s1=1LL*s1*p_inv(k,x)%mod;
    74         s2=1LL*s2*p_inv(k,m-y+1)%mod;
    75         ans=(ans+mod-1LL*s1*s2%mod)%mod;
    76     }
    77     printf("%d",ans);
    78 } 
    View Code
  • 相关阅读:
    找零问题-完全背包
    可同时在nodejs和浏览器端使用的websocket
    C++ vector 比较大小
    npm ERR! Unexpected token in JSON at position 0 while parsing near '<HTML> 解决办法
    C/C++宏定义中#与##区别
    解析日志工具。
    3
    2
    dssfsfsfs
    android获取USB设备的名称
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13939746.html
Copyright © 2011-2022 走看看