COGS 2752. [济南集训 2017] 数列运算
2752. [济南集训 2017] 数列运算
dp[i]表示到第i个数的答案
枚举前一个加号在j后面
那么到j一共有2^(j-1)种方案,每种方案在j后面都是一个加号,加号后面全是乘号
dp[i]=Σ(dp[j]+2^(j-1)*(a[j+1]*a[j+2]……*a[i]))
这样复杂度为0(n³)
看到a[j+1]*a[j+2]……*a[i] 可以预处理一下前缀积
这样可以优化到0(n²)
如果是前缀和的话就可以取a[i]-a[j]
前缀积就要取a[i]/a[j]
显然,这个数很大需要取模 但是取模下的除法不能随便乱用
而一个数mod p 意义下的逆元等于这个数的倒数(此倒数非彼倒数)
所以就可以a[i]乘它的逆元,预处理一下每个位置的逆元
就优化完了
因为枚举j,要求和,所以可以用前缀和优化一下,复杂度变成0(n)
1 #include<cstdio> 2 #include<cstring> 3 #define mod 1000000007 4 using namespace std; 5 int n,a[100001]; 6 long long cf[100001]; 7 long long dp[100001],pre[100001],inv[100001]; 8 9 long long pow(long long a,long long b) 10 { 11 long long res=1; 12 while(b){ 13 if(b&1) 14 res=res*a%mod; 15 a=a*a%mod; 16 b>>=1; 17 } 18 return res; 19 } 20 int main() 21 { 22 freopen("sequenceQBXT.in","r",stdin); 23 freopen("sequenceQBXT.out","w",stdout); 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 26 cf[0]=1; pre[0]=1; 27 for(int i=1;i<=n;i++) cf[i]=cf[i-1]*2%mod; 28 long long tot; 29 for(int i=1;i<=n;i++) pre[i]=pre[i-1]*a[i]%mod; 30 for(int i=1;i<=n;i++) inv[i]=pow(pre[i],mod-2); 31 long long sum1=0,sum2=1; 32 for(int i=1;i<=n;i++) 33 { 34 dp[i]=(sum1+sum2*pre[i]%mod)%mod; 35 sum1=(sum1+dp[i])%mod; 36 sum2=(sum2+cf[i-1]%mod*inv[i]%mod)%mod; 37 } 38 printf("%lld",dp[n]); 39 }