solution:
恶心题。考点:位运算 + 模拟。
我们将比赛分成两类:第一种是严格的胜利,即赢家的获胜位置严格小于输家的获胜位置。第二种是非严格的胜利,这意味着球员在球场上的获胜位置是相等的。
现在问题转化为在一个 3 列的网格上统计。提供 k c z n o l kcznol kcznol 大佬的 O ( n ) O(n) O(n) 算法,暴踩标算:
- 从左往右扫一遍,对于这一列的每个球员是第一次出现,那么我们统计 ( i + 1 , n ) (i+1,n) (i+1,n) 的答案;否则直接跳过。具体我们要维护 c n t [ 8 ] [ 3 ] cnt[8][3] cnt[8][3] 表示在状态 m a s k mask mask 的第 i i i 行排的最小且球场编号最小的球员的位置。
- 现在我们计算非严格胜利。枚举 i i i , i 2 i2 i2 行 ( i < i 2 ) (i<i2) (i<i2) , 如果 x x x, y y y 都不等于 0 0 0 ( x ≠ y ) (x\ne y) (x=y), 我们可以枚举 i 3 ∈ [ 0 , 2 ] i3\in [0,2] i3∈[0,2] , 使得在输家位置最靠前的情况下场地编号最小,就可以比较出 x x x , y y y 的结果。
常数大概有 2 3 ∗ 3 ∗ 3 = 72 2^3*3*3=72 23∗3∗3=72 。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
using namespace std;
const int mx=1e5+5;
int n,a[3][mx],id[mx][3],cnt[8][3],ans[mx];
ll ans2[3];
int in[mx];
//转化为一个三行的表格,然后求啥 ?
inline int read() {
int x=0; char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x;
}
void add(int j,int w) {
for(int s=1;s<=7;s++) {
int mn_i=-1;
for(int i=0;i<=2;i++) {
if(s>>i&1&&(mn_i==-1||id[j][i]<id[j][mn_i])) mn_i=i;
}
cnt[s][mn_i]+=w;
}
}
signed main() {
// freopen("data.in","r",stdin);
n=read();
for(int i=0;i<=2;i++) {
for(int j=1;j<=n;j++) {
id[a[i][j]=read()][i]=j;
}
}
for(int j=1;j<=n;j++) add(j,1);
for(int j=1;j<=n;j++) {
for(int i=0;i<=2;i++) {
if(in[a[i][j]]) a[i][j]=0; //player a[i][j] 已经计算过了
else {
add(a[i][j],-1);
for(int i1=i;i1<=2;i1++) {
//in[x] : 状压
if(a[i1][j]==a[i][j]) {
in[a[i][j]]|=1<<i1;
}
}
}
}
for(int i=0;i<=2;i++) {
if(a[i][j]) {
int x=a[i][j];
//cnt[i][j] 记录 状态为 i 的当中最优决策为 j 的 player 个数
for(int t=0;t<=2;t++) {
ans2[t]+=cnt[in[x]][t];
ans[x]+=cnt[in[x]][t];
}
for(int i1=i+1;i1<=2;i1++) {
//对于非严格的处理(我们首先比较败者名次靠前,再比较场地编号)
if(a[i1][j]) {
int y=a[i1][j];
PII mn={n+1,n+1};
for(int t=0;t<=2;t++) {
//此处 x 取得最优,当前得到的点对为 (id[y][t], t)
if(id[x][t]==j) {
mn=min(mn,{id[y][t],t});
}
//此处 y 取得最优,当前得到的点对为 (id[x][t], t)
if(id[y][t]==j) {
mn=min(mn,{id[x][t],t});
}
}
//得到所举办的场地
ans2[mn.second]++;
ans[id[x][mn.second]==j?x:y]++;
}
}
}
}
}
printf("%lld %lld %lld\n",ans2[0],ans2[1],ans2[2]);
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}