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 }
View Code

 

posted @ 2017-09-13 17:25  Alex丶Baker  阅读(143)  评论(0编辑  收藏  举报