官解
Problem
给定一个长度为
N 的序列
a1,a2,⋯,an,求以下表达式的值:
k=1∑n{ak+i=1∑k−1j=1∑k−1[(l=1∏ial2i−l)(l=1∏jal2j−l)]}
Solution
a=l∑rb=l∑r[f(a)f(b)]=[a=l∑rf(a)][b=l∑rf(b)]
对于第二个
∑,
f(a) 可视作常量,于是便可以提出来,得到
a=l∑rb=l∑r[f(a)f(b)]=a=l∑r[f(a)b=l∑rf(b)]
而对第一个
∑ 来说,
∑b=lrf(b) 又可视作常量,提出来得到
a=l∑rb=l∑r[f(a)f(b)]=[a=l∑rf(a)][b=l∑rf(b)]
证毕。
原式
观察到原式中有重复部分,所以我们考虑构造函数,令
f(x)=l=1∏xal2x−l
所以原式即为
k=1∑n[ak+i=1∑k−1j=1∑k−1f(i)f(j)]
k=1∑n{ak+[i=1∑k−1f(i)][j=1∑k−1f(j)]}
由于中括号中的式子相同,所以原式得
k=1∑n{ak+[i=1∑k−1f(i)]2}
如果知道了
f(i) 的值,中括号和大括号就可以通过前缀和来计算,所以现在再来观察
f(i) 部分。考虑进行递推,注意到
f(i)===l=1∏ial2i−lai2i−i×l=1∏i−1(al2i−1−l)2ai×f(i−1)2
于是我们就得到了递推式,边界条件为
f(0)=1。
自此,这道题就没有了难点,使用基本前缀和即可完成。
Code
CPPconst int N=5e6+99,mod=1e9+7;
inline int read(){
int x=0;
bool f=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x;
}
int n;
signed main(){
n=read();
int mul=1;
int ans=0;
int fsum=0;
for(int i=1;i<=n;i++){
int x;
x=read();
mul=mul*mul%mod*x%mod;
ans=(ans+x+fsum*fsum%mod)%mod;
fsum=(fsum+mul)%mod;
}
cout<<ans<<endl;
return 0;
}