首先有个显然的性质,任意两个点之间的距离不会超过2*颜色数-1
证明的话考虑路径序列中同种颜色的点不会超过2个
然后我就跑偏了,想着去造一个颜色数相关的新图,每个点带权什么的去算….
正解还是挺喵的
考虑一对点(u,v)之间的距离
d(u,v)
d
(
u
,
v
)
,令
dis[p][c]
d
i
s
[
p
]
[
c
]
表示p到颜色c的最短距离,有
d(u,v)=min(|u−v|,dis[u][c]+dis[v][c]+1)
d
(
u
,
v
)
=
m
i
n
(
|
u
−
v
|
,
d
i
s
[
u
]
[
c
]
+
d
i
s
[
v
]
[
c
]
+
1
)
这个柿子的意思是如果u到v只走第一类边,距离就是|u-v|,否则一定走了至少一条第二类边,枚举这条边在哪个颜色中,距离就是他们分别到c的距离+1
那么我们枚举编号较大的点v,枚举u,再枚举一个颜色计算距离,我们就能在 O(n2alpha) O ( n 2 a l p h a ) 的复杂度内算出所有距离的点对数(alpha是颜色数)
但这样显然太慢了
我们枚举点u时,对于同种颜色的点,很多点是相似的,完全没有必要一个一个枚举
注意到这样一个性质
令
disc[c1][c2]
d
i
s
c
[
c
1
]
[
c
2
]
表示颜色c1到颜色c2的最短距离,令
col[p]
c
o
l
[
p
]
表示点p的颜色
有
disc[col[p]][c]<=dis[p][c]<=disc[col[p]][c]+1
d
i
s
c
[
c
o
l
[
p
]
]
[
c
]
<=
d
i
s
[
p
]
[
c
]
<=
d
i
s
c
[
c
o
l
[
p
]
]
[
c
]
+
1
,
即
dis[p][c]
d
i
s
[
p
]
[
c
]
只有可能是
disc[col[p]][c],disc[col[p]][c]+1
d
i
s
c
[
c
o
l
[
p
]
]
[
c
]
,
d
i
s
c
[
c
o
l
[
p
]
]
[
c
]
+
1
这两个中的一个
我们做个差分,用一个alpha位的二进制状态mask表示这个差分,那么就可以用
f[i][c][mask]
f
[
i
]
[
c
]
[
m
a
s
k
]
表示< i的点中,颜色为c的,和其它颜色的差分状态为mask的点数,这些点和后面的点的距离是相同的,将它们合并在一起处理
于是我们就将这题做到了
O(nalpha22alpha)
O
(
n
a
l
p
h
a
2
2
a
l
p
h
a
)
算距离那里可以枚举颜色bfs一下,复杂度可以做到
O(nalpha)
O
(
n
a
l
p
h
a
)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 210000;
const int mask = 1<<8;
const int maxc = 8;
int n;
char str[maxn];
int col[maxn];
vector<int>V[maxc];
int disp[maxc][maxn],disc[maxc][maxc];
queue<int>q;
int f[maxc][mask];
ll ans[maxc*3];
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
scanf("%d",&n);
scanf("%s",str);for(int i=0;i<n;i++) col[i+1]=str[i]-'a';
for(int i=1;i<=n;i++) V[col[i]].push_back(i);
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++) disc[i][j]=maxc*2;
disc[i][i]=0;
for(int j=1;j<=n;j++) disp[i][j]=maxc*2;
for(int j=0;j<V[i].size();j++)
{
int x=V[i][j];
disp[i][x]=0,q.push(x);
}
while(!q.empty())
{
const int x=q.front(); q.pop();
int nc=disp[i][x]+1,cx=col[x];
if(disc[i][cx]==maxc*2)
{
disc[i][cx]=disp[i][x];
for(int j=0;j<V[cx].size();j++)
{
int y=V[cx][j];
if(disp[i][y]==maxc*2) disp[i][y]=nc,q.push(y);
}
}
if(x<n&&disp[i][x+1]==maxc*2) disp[i][x+1]=nc,q.push(x+1);
if(x>1&&disp[i][x-1]==maxc*2) disp[i][x-1]=nc,q.push(x-1);
}
}
for(int i=2;i<=n;i++)
{
int j=i-maxc*2;
if(j>0)
{
int cj=col[j],s=0;
for(int k=0;k<maxc;k++) s|=(disp[k][j]-disc[k][col[j]])<<k;
f[cj][s]++;
}
for(int k=max(1,j+1);k<i;k++)
{
int dis=i-k;
for(int c=0;c<maxc;c++) dis=min(dis,disp[c][k]+disp[c][i]+1);
ans[dis]++;
}
for(int c=0;c<maxc;c++)
{
for(int s=0;s<mask;s++) if(f[c][s])
{
int dis=maxc*2-1;
for(int k=0;k<maxc;k++) dis=min(dis,disc[c][k]+(s>>k&1)+1+disp[k][i]);
ans[dis]+=f[c][s];
}
}
}
for(int i=maxc*2;i>=0;i--) if(ans[i]) return printf("%d %lld\n",i,ans[i]),0;
return 0;
}