题解 礼物
首先发现直径 \(\leqslant 15\)
于是有个 \(O(15\frac{n^2}{w})\) 的做法是对每个点维护走 \(j\) 步能到达的点集
然后正解:
发现走法也就那么几种:一个一个走或者用中转颜色跳一下
于是令 \(f_{i, j}\) 为从 i 走到颜色为 j 的点的最短路径
令 \(g_{i, j}\) 为从颜色 i 走到颜色 j 的最短路径
对于两个点 \(i, j\),有 \(dis(i, j)=\min(|i-j|, f_{i, c}+f_{j, c}+1)\)
后面那个东西仍然枚举不起,然而我们发现不同的 \(f_{i, c},f_{j, c}\) 组合一共没有几种
具体地,有 \(g_{s_i, c}\leqslant f_{i, c}\leqslant g_{s_i, c}+1\)
于是可以状压预处理出 \((82^8)^2\) 种组合
然后对每个 \(i\) 枚举它前面 15 个爆扫,更远的就枚举状态就好了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define fir first
#define sec second
#define ll long long
//#define int long long
int n;
char s[N];
#if 0
namespace force{
bool vis[N];
int head[N], dis[N], ecnt;
priority_queue<pair<int, int>> q;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}
void dij(int s) {
memset(vis, 0, sizeof(vis));
memset(dis, 127, sizeof(dis));
dis[s]=0;
q.push({0, s});
while (q.size()) {
pair<int, int> u=q.top(); q.pop();
if (vis[u.sec]) continue;
vis[u.sec]=1;
for (int i=head[u.sec],v; ~i; i=e[i].next) {
v = e[i].to;
if (dis[u.sec]+1<dis[v]) {
dis[v]=dis[u.sec]+1;
q.push({-dis[v], v});
}
}
}
}
void solve() {
memset(head, -1, sizeof(head));
for (int i=1; i<=n; ++i) {
for (int j=1; j<=n; ++j) if (i!=j) {
if (abs(i-j)==1 || s[i]==s[j]) add(i, j);
}
}
ll ans1=0, ans2=0;
for (int i=1; i<=n; ++i) {
dij(i);
int maxn=0, cnt=0;
for (int j=1; j<=n; ++j) maxn=max(maxn, dis[j]);
for (int j=1; j<=n; ++j) if (maxn==dis[j]) ++cnt;
if (maxn>ans1) ans1=maxn, ans2=cnt;
else if (maxn==ans1) ans2+=cnt;
}
assert(!(ans2&1));
cout<<ans1<<' '<<ans2/2<<endl;
}
}
#endif
namespace task1{
bitset<5010> f[5010][17], st[17];
void solve() {
//cout<<double(sizeof(f)+sizeof(st))/1000/1000<<endl;
for (int i=1; i<=n; ++i) f[i][0][i]=1, st[s[i]-'a'][i]=1;
int j;
for (j=1; ; ++j) {
bool any=0;
for (int i=1; i<=n; ++i) {
f[i][j]|=f[i][j-1]|f[i-1][j-1]|f[i+1][j-1]|st[s[i]-'a'];
if (f[i][j].count()!=n) any=1;
}
for (int i=1; i<=n; ++i) st[s[i]-'a']|=f[i][j];
if (!any) break;
}
ll ans=0;
for (int i=1; i<=n; ++i) ans+=n-f[i][j-1].count();
assert(!(ans&1));
cout<<j<<' '<<ans/2<<endl;
}
}
namespace task{
ll cnt;
pair<int, int> st[N];
int f[N][8], g[8][8], h[8][1<<8][8][1<<8], mp[8][1<<8], maxn;
void solve() {
memset(f, 0x3f, sizeof(f));
memset(g, 0x3f, sizeof(g));
memset(h, 0x3f, sizeof(h));
for (int i=1; i<=n; ++i) s[i]-='a';
for (int i=0; i<8; ++i) g[i][i]=0;
for (int i=1; i<=n; ++i)
for (int j=max(1, i-15); j<=min(n, i+15); ++j) {
f[i][s[j]]=min(f[i][s[j]], abs(i-j));
g[s[i]][s[j]]=min(g[s[i]][s[j]], abs(i-j));
g[s[j]][s[i]]=min(g[s[j]][s[i]], abs(i-j));
}
for (int k=0; k<8; ++k)
for (int i=0; i<8; ++i)
for (int j=0; j<8; ++j)
g[i][j]=min(g[i][j], g[i][k]+g[k][j]+1);
for (int i=1; i<=n; ++i)
for (int j=0; j<8; ++j)
for (int k=0; k<8; ++k)
f[i][k]=min(f[i][k], f[i][j]+g[j][k]+1);
#if 0
cout<<"---f---"<<endl;
for (int i=1; i<=n; ++i) {for (int j=0; j<8; ++j) cout<<setw(5)<<f[i][j]<<' '; cout<<endl;}
cout<<"---g---"<<endl;
for (int i=0; i<8; ++i) {for (int j=0; j<8; ++j) cout<<setw(5)<<g[i][j]<<' '; cout<<endl;}
#endif
for (int i=0; i<8; ++i)
for (int s=0; s<(1<<8); ++s)
for (int j=0; j<8; ++j)
for (int t=0; t<(1<<8); ++t)
for (int k=0; k<8; ++k)
h[i][s][j][t]=min(h[i][s][j][t], g[i][k]+bool(s&(1<<k))+g[j][k]+bool(t&(1<<k))+1);
for (int i=1; i<=n; ++i) {
st[i].fir=s[i];
for (int j=0; j<8; ++j)
if (f[i][j]==g[s[i]][j]+1) st[i].sec|=1<<j;
}
for (int i=1; i<=n; ++i) {
for (int j=max(1, i-15); j<i; ++j) {
int len=min(i-j, h[st[i].fir][st[i].sec][st[j].fir][st[j].sec]);
//cout<<"ij: "<<i<<' '<<j<<' '<<len<<endl;
if (len>maxn) maxn=len, cnt=1;
else if (len==maxn) ++cnt;
}
for (int j=0; j<8; ++j)
for (int t=0; t<(1<<8); ++t) if (mp[j][t]) {
int len=h[st[i].fir][st[i].sec][j][t];
if (len>maxn) maxn=len, cnt=mp[j][t];
else if (len==maxn) cnt+=mp[j][t];
}
if (i>15) ++mp[st[i-15].fir][st[i-15].sec];
}
cout<<maxn<<' '<<cnt<<endl;
}
}
signed main()
{
freopen("gift.in", "r", stdin);
freopen("gift.out", "w", stdout);
scanf("%d%s", &n, s+1);
//force::solve();
task::solve();
return 0;
}