1. 程式人生 > >陣列分拆

陣列分拆

 

 

 

時間限制:10000ms

單點時限:1000ms

記憶體限制:256MB

描述

小Ho得到了一個數組作為他的新年禮物,他非常喜歡這個陣列!

在仔細研究了幾天之後,小Ho成功的將這個陣列拆成了若干段,並且每段的和都不為0!

現在小Ho希望知道,這樣的拆分方法一共有多少種?

兩種拆分方法被視作不同,當且僅當陣列斷開的所有位置組成的集合不同。

輸入

每組輸入的第一行為一個正整數N,表示這個陣列的長度

第二行為N個整數A1~AN,描述小Ho收到的這個陣列

對於40%的資料,滿足1<=N<=10

對於100%的資料,滿足1<=N<=105, |Ai|<=100

輸出

對於每組輸入,輸出一行Ans,表示拆分方案的數量除以(109+7)的餘數。

樣例輸入

5
1 -1 0 2 -2

樣例輸出

5

dalao 思路:http://hihocoder.com/discuss/question/5645

開始很容易直接想到一個O(n^2) 的動態規劃。 令dp[i]表示i個數不同種劃分數,sum[j,i]表示陣列下標從j到i的和。 從劃分思想,比較容易想到:

dp[i]=∑dp[j] (j<i&&sum[j,i]!=0)

其中sum[j,i]可以由字首陣列O(1)的得到。

但明顯這題N<1e5,複雜度不夠。 繼續優化。 對於dp[i]求和這一步我們同樣用字首陣列優化。 定義: dp_sum[i] = ∑ dp[i]

那麼對於dp[i] = dp_sum[i-1] - 數量(∑ sum[j+1,i]=0)

對於sum[j+1,i]=0,我們兩邊同時加上sum[0,j],就變成:sum[0,i] = sum[0,j]。問題變成減去出現sum[0,i] = sum[0,j]的數量,也就是減去字首和為sum[0,i]的數量。 ``於是我們只需要一個Hash表去儲存字首和sum[0,i]出現的個數。時間複雜度O(1)求出sum[0,i]的數量。

則轉移方程:dp[i] = dp_sum[i-1] - Hash[sum[0,i]]

 

 

o(n^2) 複雜度 超時

package Daily;

import java.util.Scanner;

public class Main_233 {
    int mod = 1000000007;
    public  void excute(){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int []nums = new int[n];
        for(int i = 0; i < n; i++){
            nums[i] = sc.nextInt();
        }
        sc.close();
        int  count = find(nums);
        System.out.println(count);
    }

    public  int find(int []nums){
        int dp[] = new int[nums.length + 1];
        dp[nums.length] = 1;
        for(int i = nums.length- 1; i >= 0; i --){
            int subSum = 0;
            int kind = 0;
            for(int k = i; k < nums.length ; i --){
                subSum += nums[k];
                if(subSum != 0 ){
                 kind += dp[k +1];
                }
            }
            dp[i] = kind;
        }
        return dp[0];
    }
    public static  void  main(String[] args){
        Main_233 m = new Main_233();
        m.excute();
    }
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
const int mod= 1e9+7;
ll dp[N],sum[N],sum_dp[N];

map<ll,ll> Hash;

int main(){
     int n;
     while(~scanf("%d",&n)){
        memset(dp,0,sizeof(dp));
        sum[0] = 0;
        for(int i=1;i<=n;i++){
          int x;scanf("%d",&x);
          sum[i] = sum[i-1] + x;
        }

        dp[0] = 1;
        sum_dp[0] = 1;
        Hash[0] = 1;
        for(int i=1;i<=n;i++){
           dp[i] = (sum_dp[i-1] - Hash[sum[i]] + mod)%mod;
           sum_dp[i] = (sum_dp[i-1] + dp[i] + mod)%mod;
           Hash[sum[i]] = (Hash[sum[i]] +dp[i] + mod)%mod;
           //cout<<dp[i]<<" ";
        }
        //cout<<endl;
        printf("%lld\n",dp[n]);
     }
}