解题思路:
暴力的话用前缀和和前缀积,遍历每个子数组,时间复杂度O(n^2)
优化:
可以想到一个数乘x和加x,只有当x等于1时,加法比乘法加得多。
第一个优化:
当从后向前遍历时,如果前面都是1,乘积依然比和大,直接返回。
可以发现如果数组中1得个数很少,第一个优化会很顺利,但当1个数很多时,最坏时间复杂度仍是O(n^2),原因在于1的重复运算。
第二个优化:预处理一个数组pre1[N],pre1[i]表示i以前连续1的个数(与i相连),遇到1就直接跳过pre1[i]个距离,使sum增加,如果sum之前小于mul,增加后大于等于mul,说明有一个解。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5; ll mod=4e10+5; ll dp[N]; int main( ) { ios::sync_with_stdio(false); cin.tie(0); int n;cin>>n; vector<int>arr(n); vector<int>pre1(n,0); ll ans=0; int num=0; for(int i=0;i<n;i++) { cin>>arr[i]; pre1[i]=num; if(arr[i]==1)num++; else num=0; } for(int i=0;i<n;i++) { ll sum=0,mul=1; for(int j=i;j>=0;j--) { mul=(mul*arr[j])%mod;sum+=arr[j]; if(mul==sum)ans++; if(mul-sum>j)break; if(pre1[j]==0)continue; if(mul<=sum) { sum+=pre1[j]; } else{ sum+=pre1[j]; if(sum>=mul)ans++; } j-=pre1[j]; } } cout<<ans; return 0; }
亲测AC~