今天看到一个处理数组子序列和很牛的一种写法
牛客小白月赛 51 平均题
这题的证明是找规律
我们假设数组的长度是4起初每一个元素的数值都是x
显然区间长度为1的答案就是s(n),s是前缀和数组
长度是2的我们可以理解为首位被加次数都是1,中间2-n-1的元素都被加了2次
1 | x | x | x | x |
2 | x | 2x | 2x | x |
3 | x | 2x | 2x | x |
4 | x | x | x | x |
长度是三的话也是首位只加一次中间的数加了两次
长度是4的话每个元素只加了一次
我们可以用图来看,这里建议大家多手动模拟一下,其实很想是差分,你要枚举的子序列长度越大的话越中间的数被加的次数也就越多
所以可以得出一个结论就是第n个长度的子序列和为ans[i]=ans[i-1]+(s[n-i+1]-s[i])
你可以理解成在上一个长度首位不动的基础上,中间的数被加的次数都多了一次
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
const int mod=1e9+7;
ll qmi(ll a,ll b,ll mod)
{
ll res=1;
while(b)
{
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
//int a[N];
void cf()
{
ll n;
cin>>n;
vector<ll>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
ll ans=0;
ll sum=0;
for(int i=1;i<=n;i++)a[i]+=a[i-1];
for (int i=1;i<=n;i++){
sum=sum+a[n-i+1]-a[i-1];
ans=(ans+sum%mod*qmi(i,mod-2,mod))%mod;
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
while(t--)
{
cf();
}
}