1. 题面梗概
中译中:给定 n 个位置的函数值,其中 ai 是隐藏的整数序列。已知所有的 f(1…n),求原序列 a。
f(x)=i=1∑nai∣i−x∣
- 2≤n≤3⋅105
- −1014≤f(i)≤1014
2. 逻辑推导
这个题看起来就不是很友善,但绝对值的核心在于 分段线性。我们可以先把柿子展开看看:
f(x)=i=1∑x(ai(x−i))+i=x+1∑n(ai(i−x))
既然是 线性 的,我们可以先差分看看性质。
df(x)=f(x+1)−f(x)=i=1∑x(ai(x+1−i))+i=x+1∑n(ai(i−x−1))−i=1∑x(ai(x−i))+i=x+1∑n(ai(i−x))
化简后得到柿子如下:记 Sx=∑i=1xai。
df(x)=i=1∑xai−i=x+1∑nai=Sx−(Sn−Sx)=2Sx−Sn
这里我们再差分一次(因为我们得到了 2Sx−Sn 这个前缀和关系,差分可以还原回正常序列)
ddf(x)=df(x)−df(x−1)=(2Sx−Sn)−(2Sx−1−Sn)=2(Sx−Sx−1)=2ax
然后我们就得到了ax 和 ddf 函数的关系了,至于两端的 a1 和 an 怎么求呢?我们可以从 df 函数的端点出发。
df(1)=2S1−Sn=2a1−Sn
df(n−1)=2Sn−1−Sn=2(Sn−an)−Sn=Sn−2an
至于这个 Sn 怎么求?我们可以从 f 函数的端点出发。
f(1)=i=1∑nai(i−1)f(n)=i=1∑nai(n−i)
那么就可以得到这个柿子了:
f(1)+f(n)=i=1∑n(ai⋅(n−1))=Sn⋅(n−1)
3. 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include <bits/stdc++.h> using namespace std; using ll = long long;
const int maxn = 3e5 + 5;
ll f[maxn]; ll df[maxn]; ll ddf[maxn]; ll a[maxn]; int n;
void solve( ) { cin >> n; for( int i = 1; i <= n; ++ i ) cin >> f[i];
ll Sn = ( f[1] + f[n] ) / ( n - 1 );
for( int i = 1; i <= n; ++ i ) df[i] = f[i + 1] - f[i];
for( int i = 1; i <= n; ++ i ) ddf[i] = df[i] - df[i - 1];
a[1] = ( Sn + df[1] ) / 2;
for( int i = 2; i <= n - 1; ++ i ) a[i] = ddf[i] / 2;
a[n] = ( Sn - df[n - 1] ) / 2; for( int i = 1; i <= n; ++ i ) cout << a[i] << " "; cout << '\n'; }
int main( ) { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int _t = 1; cin >> _t; while( _t -- ) solve( ); return 0; }
|
4. 复盘