【题解】「BalticOI 2022 Day2」Boarding Passes
这题题意有点不清楚。就是我们需要在所有人开始上船之前就确定小组顺序和每个人的方向。而不是在知道小组中每个人的顺序后再决策。
观察到
那么我们就需要快速计算贡献,如果组
我们直接跑个前缀和
对于组内贡献,依然按上面的定义,只不过贡献变成
状压 DP,然后转移的时候枚举分割点。由于
#define N 100005
int n, a[15][N], sz[N], m = 14, s = (1 << 15) - 1; LL f[N], u[15][15][N], v[15][15][N], c[15][N];
char ch[N];
LL calc(int w,int p,int x){
LL sum = 0;
rep(i, 0, m)if(1 & (w >> i))sum += u[p][i][x] * 2;
return sum + u[p][p][x];
}
LL value(int w,int p,int x){
LL sum = 0;
rep(i, 0, m)if(1 & (w >> i))sum += v[p][i][x] * 2;
return sum + v[p][p][x];
}
LL g(int w,int p,int x){
return calc(w, p, x) + value(w, p, x + 1);
}
int main() {
scanf("%s", ch + 1);
n = strlen(ch + 1);
rp(i, n){
int op = ch[i] - 'A';
c[op][i]++, a[op][++sz[op]] = i;
rep(j, 0, m)c[j][i] += c[j][i - 1];
}
rep(x, 0, m)rep(y, 0, m){
rp(i, n){
u[x][y][i] = u[x][y][i - 1];
if(ch[i] - 'A' == x)u[x][y][i] += c[y][i - 1];
}
pr(i, n){
v[x][y][i] = v[x][y][i + 1];
if(ch[i] - 'A' == x)v[x][y][i] += c[y][n] - c[y][i];
}
}
memset(f, 0x3f, sizeof(f));
f[0] = 0;
rep(i, 0, s - 1)rep(j, 0, m)if(! (1 & (i >> j))){
int t = i | (1 << j);
int l = 0, r = sz[j] - 1, ed = sz[j];
while(l <= r){
int mid = (l + r) >> 1;
if(g(i, j, a[j][mid]) < g(i, j, a[j][mid + 1]))ed = mid, r = mid - 1;
else l = mid + 1;
}
cmn(f[t], f[i] + g(i, j, a[j][ed]));
}
cout << f[s] / 2;
if(f[s] & 1)pc('.'), pc('5');
return 0;
}