推式子 + 求解线性方程组
根据题意,由于
{ b } \{b\} { b } 序列共有
n n n 项且对于每个
b i b_i b i 都可以用含
a 1 ∼ n a_{1 \sim n} a 1 ∼ n 的式子来表示,即有
n n n 个线性方程以及
n n n 个未知量
a 1 ∼ n a_{1 \sim n} a 1 ∼ n ,显然容易想到联立线性方程求解。
对于这种问题我们应该如何考虑呢?首先光瞪眼肯定是不行的,你需要列出来看看规律。为了避免被绕晕,你需要列出
n n n 行先,然后依次对
i ∈ [ 1 , 2 , ⋯ , n ] i \in [1,2,\cdots,n] i ∈ [ 1 , 2 , ⋯ , n ] 进行考虑,把
a i a_i a i 对应在每一行产生的贡献加进去(从第
i i i 行权值为
1 1 1 开始进行依次考虑这样可以很方便地表示出来,就不会乱),注意每一个
b i b_i b i 对应的所有
a a a 的表示要对齐即可,这样方便观察数量的性质以及便于进行计算。当然我们可以不需要把
n n n 行都具体地列出来,比如我们可以只列出前两行和最后一行,已经足够我们观察了。
列出方程组如下:
{ b 1 = a 1 + n a 2 + ( n − 1 ) a 3 + ⋯ + 2 a n b 2 = 2 a 1 + a 2 + n a 3 + ⋯ + 3 a n ⋮ b n = n a 1 + ( n − 1 ) a 2 + ( n − 2 ) a 3 + ⋯ + a n \begin{cases}
b_1=a_1+na_2+(n-1)a_3+\cdots+2a_n
\\
b_2=2a_1+a_2+na_3+\cdots+3a_n
\\
\vdots
\\
b_n=na_1+(n-1)a_2+(n-2)a_3+\cdots+a_n
\end{cases} ⎩ ⎨ ⎧ b 1 = a 1 + n a 2 + ( n − 1 ) a 3 + ⋯ + 2 a n b 2 = 2 a 1 + a 2 + n a 3 + ⋯ + 3 a n ⋮ b n = n a 1 + ( n − 1 ) a 2 + ( n − 2 ) a 3 + ⋯ + a n
不能考虑高斯消元求解线性方程组,因为高斯消元法时间复杂度为
O ( n 3 ) O(n^3) O ( n 3 ) 会 TLE,考虑观察法解方程组。
观察不难发现:
b i − b i − 1 = ∑ k = 1 n a k − n ⋅ a i b_{i}-b_{i-1}=\sum_{k=1}^na_k- n \cdot a_i b i − b i − 1 = k = 1 ∑ n a k − n ⋅ a i
即:
a i = ∑ k = 1 n a k − ( b i − b i − 1 ) n a_i =\dfrac{\sum_{k=1}^na_k - (b_i-b_{i-1})}{n} a i = n ∑ k = 1 n a k − ( b i − b i − 1 )
显然我们只要知道
∑ k = 1 n a k \sum_{k=1}^na_k ∑ k = 1 n a k 的值,我们就可以解出每一个
a i a_i a i ,于是接下来我们的任务就是求解
∑ k = 1 n a k \sum_{k=1}^na_k ∑ k = 1 n a k 的值。
观察线性方程组不难发现,对这个线性方程组左右部分相加可得:
∑ i = 1 n b i = ∑ i = 1 n ( ∑ j = 1 n j × a i ) \sum_{i=1}^nb_i = \sum_{i=1}^n \Bigg(\sum_{j=1}^nj \times a_i \Bigg) i = 1 ∑ n b i = i = 1 ∑ n ( j = 1 ∑ n j × a i )
和式变换交换求和次序即:
∑ i = 1 n b i = ( ∑ j = 1 n j ) × ( ∑ i = 1 n a i ) \sum_{i=1}^nb_i = \Bigg(\sum_{j=1}^n j \Bigg) \times \Bigg(\sum_{i=1}^n a_i \Bigg) i = 1 ∑ n b i = ( j = 1 ∑ n j ) × ( i = 1 ∑ n a i )
考虑等差数列求和公式化简,即:
∑ i = 1 n b i = n ( 1 + n ) 2 × ∑ i = 1 n a i \sum_{i=1}^nb_i =\dfrac{n(1+n)}{2} \times \sum_{i=1}^n a_i i = 1 ∑ n b i = 2 n ( 1 + n ) × i = 1 ∑ n a i
故:
∑ i = 1 n a i = ∑ i = 1 n b i × 2 n ( 1 + n ) \sum_{i=1}^n a_i = \sum_{i=1}^nb_i \times \dfrac{2}{n(1+n)} i = 1 ∑ n a i = i = 1 ∑ n b i × n ( 1 + n ) 2
于是
∑ k = 1 n a k \sum_{k=1}^na_k ∑ k = 1 n a k 也求解出来了。
回顾思路:先计算出
∑ k = 1 n a k \sum_{k=1}^n a_k ∑ k = 1 n a k ,然后依次枚举
i ∈ [ 1 , n ] i \in [1,n] i ∈ [ 1 , n ] ,看一下是否都满足
a i = ∑ k = 1 n a k − ( b i − b i − 1 ) n a_i =\dfrac{\sum_{k=1}^na_k - (b_i-b_{i-1})}{n} a i = n ∑ k = 1 n a k − ( b i − b i − 1 ) 可被整除且为整数,只要存在一项不满足则无解。
然后你会发现,要计算
a i a_i a i 时需要用到
b i b_i b i 和
b i − 1 b_{i-1} b i − 1 ,那么对于
a 1 a_1 a 1 该如何计算呢?观察一开始的线性方程组你会发现,满足
a 1 = ∑ k = 1 n a k − ( b 1 − b n ) n a_1 =\dfrac{\sum_{k=1}^na_k - (b_1-b_{n})}{n} a 1 = n ∑ k = 1 n a k − ( b 1 − b n ) ,你可以单独对
a 1 a_1 a 1 进行处理,也可以就在循环中用一个
l s t lst l s t 变量来灵活处理,可见代码。
此外,对于无解的判定还有以下两个细节:
注意考虑 a i = ∑ k = 1 n a k − ( b i − b i − 1 ) n a_i =\dfrac{\sum_{k=1}^na_k - (b_i-b_{i-1})}{n} a i = n ∑ k = 1 n a k − ( b i − b i − 1 ) 这个式子除完后可能为 0 0 0 的情况。
判断 ∑ i = 1 n a i = ∑ i = 1 n b i × 2 n ( 1 + n ) \sum_{i=1}^n a_i = \sum_{i=1}^nb_i \times \dfrac{2}{n(1+n)} ∑ i = 1 n a i = ∑ i = 1 n b i × n ( 1 + n ) 2 这个的表示是否合法,因为给定的 { b } \{b\} { b } 数组不一定符合条件。
CPP typedef long long LL;
const int N=4e4 +5 ;
int n;
int a[N],b[N];
void solve () {
cin>>n;
rep (i,1 ,n) cin>>b[i];
LL S=0 ;
rep (i,1 ,n) S+=b[i];
if (S*2 %(n*(n+1 ))!=0 ) return cout<<"NO" ,void ();
S=S*2 /(n*(n+1 ));
rep (i,1 ,n){
int lst=(i-1 )%n;
if (!lst) lst=n;
LL x=S-(b[i]-b[lst]);
if (x%n!=0 || x/n<=0 ) return cout<<"NO" ,void ();
a[i]=x/n;
}
cout<<"YES" <<endl;
rep (i,1 ,n) cout<<a[i]<<" " ;
}