zoukankan      html  css  js  c++  java
  • [cf718E]Matvey's Birthday

    考虑$i$到$j$的最短路,记作$dis(i,j)$,令字符集大小为$T=8$,有$dis(i,j)<2T$

    证明:

    记$l=dis(i,j)$,假设这条最短路依次经过$a_{0},a_{1},...,a_{l}$(其中$a_{0}=i,a_{l}=j$)

    若存在$0le i<j<kle l$,满足$s_{a_{i}}=s_{a_{j}}=s_{a_{k}}$,显然此时直接从$a_{i}$到$a_{k}$更短

    即每一种字符最多出现两次,根据抽屉原理,即有$l<2T$

    更进一步的,对其分两类讨论:

    1.没有使用第2类边,那么显然是$|i-j|$

    2.使用了第2类边,假设是这条边是$(a,b)$,则$dis(i,j)=min_{(a,b)}dis(i,a)+dis(b,j)+1$

    考虑先枚举$s_{a}=s_{b}=c$,此时不难发现$a$和$b$独立,即可以对$a$和$b$分别取$dis(i,a)$和$dis(b,j)$最小

    更具体的,记$f_{i,c}=min_{s_{j}=c}dis(i,j)$,即$dis(i,j)=min_{c}f_{i,c}+f_{j,c}+1$

    综上,即
    $$
    dis(i,j)=min(|i-j|,min_{c}f_{i,c}+f_{j,c}+1)
    $$
    关于如何计算$f_{i,c}$,枚举$c$并从该种字符的位置出发进行bfs,第2类边显然仅允许第一次搜到该颜色时走,因此单次复杂度为$(n)$,总复杂度为$o(nT)$

    此时,考虑暴力从大到小枚举直径$din [1,2T)$,并求出最短路大于等于$d$的点对数,若不为0则此时的$d$以及求出的点对数即为答案

    考虑如何求最短路大于等于$d$的点对数,即$|i-j|ge d$且$min_{c}f_{i,c}+f_{j,c}+1ge d$的$(i,j)$对数

    先考虑第二个条件,即$min_{c}f_{i,c}+f_{j,c}+1ge d$

    构造$g_{c_{1},c_{2}}=min_{s_{i}=c_{1}}f_{i,c_{2}}$,显然可以$o(nT)$计算,同时有以下性质:$g_{s_{i},c}le f_{i,c}le g_{s_{i},c}+1$

    左半部分是根据$g_{c_{1},c_{2}}$的定义,在求$min$时取$i$即可

    右半部分考虑$f_{i,c}$第一次直接从$i$开始走第2类边,即为$g_{s_{i},c}+1$

    由此,将$f_{i,c}-g_{s_{i},c}$看作二进制上的某一位,即压成了一个$2^{T}$的二进制数

    对于每一个$i$,令这个二进制数为$state_{i}$,则通过$(s_{i},state_{i})$即可确定所有$f_{i,c}$,进而也可以确定判定结果,那么不妨去枚举$(s_{i},state_{i})$,再预处理其数量即可

    统计出每一个状态的数量,并对每两个状态都求出$min_{c}f_{i,c}+f_{j,c}+1$(因为$d$会变化),由于预处理时$d$不变化,$d$变化时通过预处理可以$o(1)$,复杂度为$o(nT+T^{3}2^{2T})$($o(nT)$是统计数量)

    再对第一个条件容斥,即减去$min_{c}f_{i,c}+f_{j,c}+1ge d$且$|i-j|<d$的$(i,j)$对数

    直接$o(nT)$枚举$i$和$j$,通过前面的预处理可以$o(1)$判定前者,复杂度为$o(nT^{2})$(对每一个$d$都要做一次)

    将两者的答案累加即可,最终总复杂度为$o(nT^{2}+T^{3}2^{2T})$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define T 8
     5 #define L 15
     6 queue<int>q;
     7 vector<int>v[T];
     8 int n,a[N],vis[N],visc[T],f[N][T],g[T][T],state[N],tot[T][1<<T],d[T][1<<T][T][1<<T];
     9 char s[N];
    10 int main(){
    11     scanf("%d%s",&n,s+1);
    12     for(int i=1;i<=n;i++)a[i]=s[i]-'a';
    13     for(int i=1;i<=n;i++)v[a[i]].push_back(i);
    14     for(int i=0;i<T;i++){
    15         if (!v[i].size()){
    16             for(int j=1;j<=n;j++)f[j][i]=0x3f3f3f3f;
    17             continue;
    18         }
    19         memset(vis,0,sizeof(vis));
    20         memset(visc,0,sizeof(visc));
    21         for(int j=0;j<v[i].size();j++){
    22             q.push(v[i][j]);
    23             vis[v[i][j]]=1;
    24         }
    25         while (!q.empty()){
    26             int k=q.front();
    27             q.pop();
    28             if ((k>1)&&(!vis[k-1])){
    29                 f[k-1][i]=f[k][i]+1;
    30                 q.push(k-1);
    31                 vis[k-1]=1;
    32             }
    33             if ((k<n)&&(!vis[k+1])){
    34                 f[k+1][i]=f[k][i]+1;
    35                 q.push(k+1);
    36                 vis[k+1]=1;
    37             }
    38             if (!visc[a[k]]){
    39                 for(int j=0;j<v[a[k]].size();j++)
    40                     if (!vis[v[a[k]][j]]){
    41                         f[v[a[k]][j]][i]=f[k][i]+1;
    42                         q.push(v[a[k]][j]);
    43                         vis[v[a[k]][j]]=1;
    44                     }
    45                 visc[a[k]]=1;
    46             }
    47         }
    48     }
    49     memset(g,0x3f,sizeof(g));
    50     for(int i=0;i<T;i++)
    51         for(int j=0;j<T;j++)
    52             for(int k=0;k<v[j].size();k++)g[j][i]=min(g[j][i],f[v[j][k]][i]);
    53     for(int i=1;i<=n;i++){
    54         for(int j=T-1;j>=0;j--)state[i]=(state[i]<<1)+(f[i][j]-g[a[i]][j]);
    55         tot[a[i]][state[i]]++;
    56     }
    57     for(int i1=0;i1<T;i1++)
    58         for(int j1=0;j1<(1<<T);j1++)
    59             for(int i2=0;i2<T;i2++)
    60                 for(int j2=0;j2<(1<<T);j2++){
    61                     d[i1][j1][i2][j2]=0x3f3f3f3f;
    62                     for(int i=0;i<T;i++){
    63                         int x=g[i1][i]+((j1&(1<<i))>0),y=g[i2][i]+((j2&(1<<i))>0);
    64                         d[i1][j1][i2][j2]=min(d[i1][j1][i2][j2],x+y+1);
    65                     }
    66                 }
    67     for(int i=L;i;i--){
    68         long long ans=0;
    69         for(int i1=0;i1<T;i1++)
    70             for(int j1=0;j1<(1<<T);j1++)
    71                 for(int i2=0;i2<T;i2++)
    72                     for(int j2=0;j2<(1<<T);j2++)
    73                         if (d[i1][j1][i2][j2]>=i)ans+=1LL*tot[i1][j1]*tot[i2][j2];
    74         for(int j=1;j<=n;j++)
    75             for(int k=max(j-i+1,1);k<=min(j+i-1,n);k++)
    76                 if (d[a[j]][state[j]][a[k]][state[k]]>=i)ans--;
    77         if (ans){
    78             printf("%d %lld",i,ans/2);
    79             return 0;
    80         }
    81     }
    82 }
    View Code
  • 相关阅读:
    数据压缩算法---LZ77算法 的分析与实现
    数据压缩算法---霍夫曼编码的分析与实现
    数据压缩的重要组成部分---位操作
    排序算法的C语言实现(上 比较类排序:插入排序、快速排序与归并排序)
    广度优先(bfs)和深度优先搜索(dfs)的应用实例
    数据结构 图的定义和搜索方法(清晰图解)
    数据结构-堆 接口定义与实现分析(详细注释与图解)
    数据结构-堆的定义描述
    数据结构 链式哈希表(Hash Table)的接口定义与实现分析(完整代码)
    SQLServer常用快捷键汇总
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14820640.html
Copyright © 2011-2022 走看看