Codeforces-1485 F. Copy or Prefix Sum(DP)

Codeforces-1485 F. Copy or Prefix Sum(DP)
思路:

  • 可以想到,结果每个位置由两种可能的值,所以理想结果应该是 2 n − 1 2^{n-1} 2n−1。但是不一定,原因是 ∑ 1 i − 1 a i = 0 ∑^{i-1}_1a_i=0 ∑1i−1​ai​=0,导致两种取法得到的结果一样。所以我们得用动态规划的方法去重。
  • 直观的动态规划思路肯定是 d p [ i ] [ j ] dp[i][j] dp[i][j]代表前缀 i i i,前缀和为 j j j时候能得到的 h y b r i d hybrid hybrid数组数目。转移就是 d p [ i ] [ j ] + = d p [ i − 1 ] [ j − b [ i ] ] , d p [ i ] [ b [ i ] ] + = d p [ i ] [ j ] dp[i][j]+=dp[i-1][j-b[i]],dp[i][b[i]]+=dp[i][j] dp[i][j]+=dp[i−1][j−b[i]],dp[i][b[i]]+=dp[i][j],不过很明显这样转移复杂度较高。我们考虑怎么通过动态规划求出重复的部分。
  • 定义 D P [ i ] DP[i] DP[i]为对于长度为 i i i的前缀存在多少个 h y b r i d hybrid hybrid数组, d p [ i ] [ j ] dp[i][j] dp[i][j]为长度为 i i i前缀中,满足 ∑ x = 1 i ( a x − b x ) = j ∑^i_{x=1}(a_x-b_x)=j ∑x=1i​(ax​−bx​)=j的方案数为 d p [ i ] [ j ] dp[i][j] dp[i][j]。当 b [ i ] = a [ i ] b[i]=a[i] b[i]=a[i]时, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j],当 b [ i ] = a [ i ] − ∑ x = 1 i − 1 a x b[i]=a[i]-∑^{i-1}_{x=1}a_x b[i]=a[i]−∑x=1i−1​ax​时, d p [ i ] [ ∑ x i − 1 ( − b x ) ] = D P [ i − 1 ] dp[i][∑^{i-1}_x(-b_x)]=DP[i-1] dp[i][∑xi−1​(−bx​)]=DP[i−1]。因为只有一次转移,其他部分都是直接继承,使用 m a p map map则可以 n l o g ( n ) nlog(n) nlog(n)的维护出 d p dp dp数组。
  • 注意到,当长度 i i i的前缀和为 ∑ x i − 1 ( − b x ) ∑^{i-1}_x(-b_x) ∑xi−1​(−bx​)时,可以得到此时 ∑ x i − 1 ( a x ) = 0 ∑^{i-1}_x(a_x)=0 ∑xi−1​(ax​)=0,所以这就等于我们第一点中说的重复取值的部分。设 s u m = ∑ x i − 1 ( − b x ) sum=∑^{i-1}_x(-b_x) sum=∑xi−1​(−bx​),则 D P [ i ] = D P [ i − 1 ] ∗ 2 − d p [ i − 1 ] [ s u m ] DP[i]=DP[i-1]*2-dp[i-1][sum] DP[i]=DP[i−1]∗2−dp[i−1][sum],这就维护出了 D P DP DP数组。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
typedef long long ll;
map<ll,ll>mp;
ll a[maxn];
int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int n;scanf("%d",&n);
        for(int i = 1;i <= n;i++) {
            scanf("%lld",&a[i]);
            a[i] += a[i - 1];
        }
        mp.clear();
        mp[0] = 1;
        ll ans = 1;
        for(int i = 1;i <= n;i++) {
            ll tmp = mp[-a[i - 1]];
            mp[-a[i - 1]] = ans;
            ans = (ans * 2 - tmp) % mod;
            if(ans < 0) ans += mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

上一篇:VS-Code用户代码片段 - 快捷生成代码


下一篇:LeetCode题解(1314):矩阵区域和(Python)