*hiho 1475 - 数组拆分,dp,由N^2降到NlogN

Posted redips

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了*hiho 1475 - 数组拆分,dp,由N^2降到NlogN相关的知识,希望对你有一定的参考价值。

题目链接

描述

小Ho得到了一个数组作为他的新年礼物,他非常喜欢这个数组!

在仔细研究了几天之后,小Ho成功的将这个数组拆成了若干段,并且每段的和都不为0!

现在小Ho希望知道,这样的拆分方法一共有多少种?

两种拆分方法被视作不同,当且仅当数组断开的所有位置组成的集合不同。

输入

每组输入的第一行为一个正整数N,表示这个数组的长度

第二行为N个整数A1~AN,描述小Ho收到的这个数组

对于40%的数据,满足1<=N<=10

对于100%的数据,满足1<=N<=105, |Ai|<=100

输出

对于每组输入,输出一行Ans,表示拆分方案的数量除以(109+7)的余数。

-----------------------------------------------------------------------------------------------------------

容易想到一个N^2的解法:

F[i] = Sum(F[0<=j<i])+(pre[i]!=0),pre[j]!=pre[i]. 其中pre[i]为前缀和。

因为N为10w,所以肯定过不了。

我们可以先不判断pre[j]是否等于pre[i],即维护一个累加和,然后再减去前缀和等于pre[i]的累加和:F[i] = 当前累加和 - pre[i]的累加和。

pre[i]的累加和用map维护,是logN的复杂度。

这样就由N^2降到了NlogN

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MOD = 1e9+7;
const int N = 100100;
int sum[N];
long long dp[N];
int main(){
    long long pre = 0;
    map<long,long> records;
    int n; cin>>n; for(int i=0;i<n;i++){
        scanf("%d",sum+i); if(i) sum[i]+=sum[i-1];
        dp[i] = sum[i]?((pre+1)%MOD):pre;
        auto iter = records.find(sum[i]);
        if(iter==records.end()) records[sum[i]]=dp[i];
        else {
            dp[i] = (dp[i]-iter->second+MOD)%MOD;
            iter->second = (iter->second+dp[i])%MOD;
        }
        pre = (pre+dp[i])%MOD;
    }
    printf("%lld\n",dp[n-1]);
    return 0;
}

 

 

以上是关于*hiho 1475 - 数组拆分,dp,由N^2降到NlogN的主要内容,如果未能解决你的问题,请参考以下文章

hihocoder 1475数组分拆

1475 建设国家 DP

hiho1044状压dp1

hiho1523 数组重排2

hiho 1617 - 方格取数 - dp

hiho一下158(hihocoder 1318)