cogs 2752. [济南集训 2017] 数列运算
2752. [济南集训 2017] 数列运算
★★☆ 输入文件:sequenceQBXT.in
输出文件:sequenceQBXT.out
简单对比
时间限制:1 s 内存限制:512 MB
【题目描述】
在纸上有一个长为n的数列,第i项值为ai。
现在小A想要在这些数之间添加加号或乘号。问对于不同的2n−1种方案,
所有答案的和是多少?
由于数据范围较大,所以输出对1000000007取模的结果。
【输入格式】
输入第一行一个整数n表示数列的长度。
之后一行n个整数,第n个整数表示数列的第i项ai。
【输出格式】
m行,第i行表示第i个询问的答案对1000000007取模的结果。
【样例输入】
3
1 2 4
【样例输出】
30
【数据范围与约定】
对于30%的数据,1≤n≤10,1≤ai≤105
对于另外30%的数据,1≤n≤1000,ai=1
对于90%的数据,1≤n≤1000,1≤ai≤105
对于100%的数据,1≤100000,1≤ai≤109
【来源】
清北学堂济南NOIP集训二试T2
思路:
一个数列,长为n
在里面加n-1个加号或乘号
问方案所有方案的数列和
有部分数据数列全为1
那么枚举有i个乘号,ans=Σ(C(n-1,2)*(n-i))
一、基本思路O(n^3)
dp[i]表示到第i个数的答案
枚举前一个加号在j后面
那么到j一共有2^(j-1)种方案,每种方案在j后面都是一个加号,加号后面全是乘号
令tot=a[j+1]*a[j+2]……*a[i]
dp[i]=Σ(dp[j]+2^(j-1)*tot)
#include<cstdio> #include<cstring> #define mod 1000000007 using namespace std; int n,a[100001]; long long cf[100001]; long long dp[100001],pre[100001],inv[100001]; long long pow(long long a,long long b){ long long res=1; while(b){ if(b&1) res=res*a%mod; a=a*a%mod; b>>=1; } return res; } int main(){ freopen("sequenceQBXT.in","r",stdin); freopen("sequenceQBXT.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); cf[0]=1; for(int i=1;i<=n;i++) cf[i]=cf[i-1]*2%mod; long long tot; pre[0]=1; for(int i=1;i<=n;i++) pre[i]=pre[i-1]*a[i]%mod; for(int i=1;i<=n;i++) inv[i]=pow(pre[i],mod-2); long long sum1=0,sum2=1; for(int i=1;i<=n;i++){ dp[i]=(sum1+sum2*pre[i]%mod)%mod; sum1=(sum1+dp[i])%mod; sum2=(sum2+cf[i-1]%mod*inv[i]%mod)%mod; } printf("%I64d",dp[n]); }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。