说在前面
me的代码警告怕是假的
本地AC提交WA
最后发现是有个地方没有赋初值?还是me开了O2才发现了这条警告…
-Wuninitialized 和 -Wmaybe-uninitialized 要你们有何用!!
题目
LOJ#2020传送门
看题可戳传送门
解法
由题,因为可以对 a a 或串加一个数,所以可以看作是 b b 不变,而随意变化
然后,假设我们已经确定了位置匹配,那么差异值就应该是
∑ni=1(x+ai−bpi)2
∑
i
=
1
n
(
x
+
a
i
−
b
p
i
)
2
其中
pi=((i+k−1)modN)+1 (k∈[0,N−1])
p
i
=
(
(
i
+
k
−
1
)
mod
N
)
+
1
(
k
∈
[
0
,
N
−
1
]
)
。
x
x
是串的变化量,记
δi=ai−bpi
δ
i
=
a
i
−
b
p
i
这个差异值是一堆二次函数相加,那么加起来还是一个二次函数,这个二次函数长这样: nx2+2x∑δi+(∑δi2) n x 2 + 2 x ∑ δ i + ( ∑ δ i 2 )
可以发现, ∑δ ∑ δ 是固定的,它的值就是 ∑ai−∑bi ∑ a i − ∑ b i ,所以 x x 的最优位置就确定了,当时,上式取最小值
然后唯一的不确定因素就是 (∑δi2) ( ∑ δ i 2 ) ,我们把它拆开,得到 ∑ai2−2aibpi+bpi2 ∑ a i 2 − 2 a i b p i + b p i 2 。于是当 ∑aibpi ∑ a i b p i 取到最大值的时候,差异也就最小了,这也就是答案
于是求
∑aibpi
∑
a
i
b
p
i
的最大值,显然可以把一个串反转,然后把另一个串复制一遍接在后面,就是一个卷积形式
比如样例:
1 2 3 4 5 1 2 3 4 5
5 4 3 3 6 0 0 0 0 0
直接跑一遍FFT即可
下面是代码
me用了一些myy论文里提到的技巧……
所以有些地方可能会比较奇怪
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const double PI2 = 3.1415926535897932384626 * 2 ;
int N , l0[50005] , l1[50005] ;
int expos[270000] , len ;
typedef struct Complex cpx ;
struct Complex{
double r , i ;
Complex( double r_ = 0 , double i_ = 0 ): r(r_) , i(i_) {} ;
cpx conj() { return cpx( r , -i ) ; }
cpx operator + ( const cpx &A ) const { return cpx( r + A.r , i + A.i ) ; }
cpx operator - ( const cpx &A ) const { return cpx( r - A.r , i - A.i ) ; }
cpx operator * ( const cpx &A ) const { return cpx( r * A.r - i * A.i , r * A.i + i * A.r ) ; }
cpx operator * ( double p ) const { return cpx( r * p , i * p ) ; }
cpx operator / ( double p ) const { return cpx( r / p , i / p ) ; }
} a[270000] , b[270000] , nil , _one = cpx( 1 , 0 ) ;
void preWork(){
for( len = 1 ; len <= N * 2 ; len <<= 1 ) ;
for( int i = 1 , now = 0 , t ; i < len ; i ++ ){
t = len >> 1 ;
while( now&t ) now ^= t , t >>= 1 ; now ^= t ;
expos[i] = now ;
}
}
void FFT( cpx *a , int len , int rev ){
for( int i = 1 ; i < len ; i ++ )
if( expos[i] > i ) swap( a[ expos[i] ] , a[i] ) ;
cpx wid , w , t0 , t1 ;
for( int i = 2 ; i <= len ; i <<= 1 ){
wid = cpx( cos( PI2 / i ) , sin( PI2 * rev / i ) ) ;
for( int j = 0 ; j < len ; j += i ){
w = _one ;
for( int k = j ; k < j + ( i >> 1 ) ; k ++ ){
t0 = a[k] , t1 = a[k+(i>>1)] * w ;
a[k] = t0 + t1 ;
a[k+(i>>1)] = t0 - t1 ;
w = w * wid ;
}
}
} if( rev == -1 ) for( int i = 0 ; i < len ; i ++ )
a[i] = a[i] / len ;
}
void solve(){
for( int i = 1 ; i <= N ; i ++ ) a[i].r = a[i+N].r = l0[i] ;
for( int i = 1 ; i <= N ; i ++ ) a[i].i = l1[N-i+1] ;
FFT( a , len , 1 ) ; b[0] = a[0].conj() ;
for( int i = 1 ; i < len ; i ++ ) b[i] = a[len-i].conj() ;
cpx t0 , t1 ;
for( int i = 0 ; i < len ; i ++ ){
t0 = a[i] , t1 = b[i] ;
a[i] = ( t0 + t1 ) / 2 ;
b[i] = cpx( 0 , -1 ) * ( t0 - t1 ) / 2 ;
a[i] = a[i] * b[i] ;
} FFT( a , len , -1 ) ;
int max_pos = N + 1 ;
for( int i = 1 ; i <= N ; i ++ )
if( a[i+N].r > a[ max_pos ].r ) max_pos = i + N ;
max_pos -= N + 1 ;
long long delta = 0 , ans = 0 , tmp , x ;
for( int i = 1 ; i <= N ; i ++ ){
tmp = l0[ (max_pos+i-1)%N+1 ] - l1[i] ;
delta += tmp ; ans += tmp * tmp ;
} if( delta > 0 ) x = -1.0 * delta / N - 0.5 ;
else x = -1.0 * delta / N + 0.5 ;
printf( "%lld" , x * x * N + 2LL * delta * x + ans ) ;
}
inline int read_(){
int rt = 0 ;
register char ch = getchar() ;
while( ch < '0' || ch > '9' ) ch = getchar() ;
while( ch >='0' && ch <='9' ) rt = ( rt << 1 ) + ( rt << 3 ) + ch - '0' , ch = getchar() ;
return rt ;
}
int main(){
N = read_() ; read_() ;
for( int i = 1 ; i <= N ; i ++ ) l0[i] = read_() ;
for( int i = 1 ; i <= N ; i ++ ) l1[i] = read_() ;
preWork() ; solve() ;
}