E - Make it Palindrome Editorial by kyopro_friends
要約:\(\sum_x f(x)\) の形の式は \(\sum_k k*|\{x \mid f(x)=k\}|\) と変形すると簡単に求められることがあります。
index は \(0\) からとします。
ペア \((i,j)\) を固定するごとに、\((A_i,A_j)\) に対する操作が答えに何度寄与するかを考えます。
ペア \((i,j)\) の寄与回数は、\(A_i=A_j\) のとき \(0\)、そうでないとき \(\min(i+1,N-j)\) です。これを \(f(i,j)\) とします。求めるものは \(\sum_{(i,j)}f(i,j)\) です。これを冒頭で述べたとおり、\(f(i,j)\) の値ごとに分けて求めることを考えます。
- \(\min(i+1,N-j)=1\) である組、つまり \(i=0\) または \(j=N-1\) であるような \((i,j)\) について考えます。
- \((0,*)\) の寄与回数の合計は、\(A_0\neq A_j\) を満たす \(0\leq j < N\) の個数の \(1\) 倍です。
- \((*,N-1)\) の寄与回数の合計は、\(A_i \neq A_{N-1}\) を満たす \(0 \leq i <N\) の個数の \(1\) 倍です。
- もし \(A_0 \neq A_{N-1}\) であれば、その分を重複して数えているため \(1\) を引きます。
- \((0,*)\) の寄与回数の合計は、\(A_0\neq A_j\) を満たす \(0\leq j < N\) の個数の \(1\) 倍です。
- \(\min(i+1,N-j)=2\) である組、つまり「\(i=1\) かつ \(j < N-1\)」または「\(i\geq 1\) かつ \(j=N-2\)」であるような \((i,j)\) について考えます。
- \((1,*)\) の寄与回数の合計は、\(A_1\neq A_j\) を満たす \(1\leq j < N-1\) の個数の \(2\) 倍です。
- \((*,N-2)\) の寄与回数の合計は、\(A_i \neq A_{N-2}\) を満たす \(1 \leq i <N-1\) の個数の \(2\) 倍です。
- もし \(A_1 \neq A_{N-2}\) であれば、その分を重複して数えているため \(2\) を引きます。
- \((1,*)\) の寄与回数の合計は、\(A_1\neq A_j\) を満たす \(1\leq j < N-1\) の個数の \(2\) 倍です。
- 以下同様
これは \(\min(i+1,N-j)\) の小さい順に求めることで以下のように実装できます
実装例 (Python)
N=int(input())
A=list(map(int,input().split()))
C=[0]*(N+1)
for x in A: C[x]+=1
ans=0
for i in range((N+1)//2):
L=A[i]
R=A[~i] # 後ろから i 番目
ans+=(N-2*i-C[L])*(i+1)
ans+=(N-2*i-C[R])*(i+1)
if L!=R: ans-=i+1
C[L]-=1
C[R]-=1
print(ans)
posted:
last update: