hiho233 數組分拆

目錄

題目1 : 數組分拆

題意分析:

1.題是什麼?

2.思路(參考自官方思路)

3.小收穫

ac代碼:


題目1 : 數組分拆

時間限制:10000ms

單點時限:1000ms

內存限制:256MB

描述

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

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

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

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

輸入

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

第二行爲N個整數A1~AN,描述小Ho收到的這個數組

對於40%的數據,滿足1<=N<=10

對於100%的數據,滿足1<=N<=10^{5}, |Ai|<=100

輸出

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

樣例輸入

5
1 -1 0 2 -2

樣例輸出

5

 

題意分析:

1.題是什麼?

    給你一個十萬大小的數組,要你將之拆分爲不同段,問每個段和都不爲0的不同拆法總數(結果求餘1e9+7)).

2.思路(參考自官方思路)

    首先一看到統計滿足條件的情況總數自然該想到dp,問題是dp數組如何設計以及dp轉移方程.

    我們這裏設原數組爲數組a,dp數組中dp[i]的意義是將a[0]~a[i-1]拆分的方法總數,則可以獲得dp數組的轉移方程如下:

        dp[i]=\sumdp[j] (0<=j<i && a[j+1]+a[j+2]+....+a[i]!=0)

    通過預處理a數組前綴和,關於a[j+1]+a[j+2]+....+a[i]!=0的判斷可以以如下方式O(1)搞定:

    (定義一個a數組前綴和數組suma,suma[i]=\suma[j] (0<=j<=i),則若suma[i]!=suma[j],則a[j+1]+a[j+2]+....+a[i]!=0)

    可是由於求和的存在,這是一個O(n^{2})的dp,仍需優化思路.

 

    這裏我們調整思路,定義一個dp數組的前綴和數組sumdp,sumdp[i]=\sumdp[j] (0<=j<=i),則狀態轉移方程可修改爲

         dp[i]=sumdp[i-1]-\sumdp[j] (0<=j<i && suma[i]==suma[j])

    我們發現其實我們可以用一個map m把所有已計算出的dp[j]以suma[j]爲鍵做一個統計,即m[x]=\sumdp[j] (0<=j<isuma[j]==x)

    則\sumdp[j] (0<=j<i && suma[i]==suma[j])的計算也可以以O(1)完成,故而如下優化爲一個O(n)的dp.

        dp[i]=sumdp[i-1]-m[suma[i]]

    實際編寫中關於dp,sumdp,suma由於只會用到上一個數據,故而我沒用數組,只用的一個int,最大化節約空間.

3.小收穫

    map中如果直接使用下標方式如m[1000]嘗試訪問鍵爲1000的值,若map中存在則正常返回存的值,可是若不存在則視爲一種插入操作,返回0的同時執行m.insert(make_pair(1000,0)),因此最好先檢查鍵是否存在,否則以下標方式訪問可能污染map.實驗代碼如下

#include <iostream>
#include <map>
using namespace std;

void solve(){
	map<int,int> m;
	m.insert(make_pair(0,1));
	cout<<"下標訪問前的map:"<<endl; 
	for(map<int,int>::iterator ite=m.begin();ite!=m.end();ite++){
		cout<<ite->first<<" "<<ite->second<<endl;
	} 
	
	cout<<endl<<"鍵爲1000的訪問返回: "<<m[1000]<<endl;//下標訪問 
	
	cout<<"下標訪問後的map:"<<endl; 
	for(map<int,int>::iterator ite=m.begin();ite!=m.end();ite++){
		cout<<ite->first<<" "<<ite->second<<endl;
	} 
}

int main(){
	solve();
	return 0;
}

ac代碼:

#include <iostream>
#include <vector>
#include <map>
using namespace std;

const int maxn=1e5+5; 
const int mod=1e9+7;
vector<int> a(maxn,0);

void solve(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];  
	
	map<int,int> m;
	m.insert(make_pair(0,1));
	int dp=1,suma=0,sumdp=1;
	for(int i=0;i<n;i++){
		suma+=a[i];
		dp=sumdp;
		if(m.count(suma)){
			dp=(dp-m[suma]+mod)%mod;//避免負數 
			m[suma]=(m[suma]+dp)%mod;
		}
		else m[suma]=dp; 
		sumdp=(sumdp+dp)%mod;
	}
	cout<<dp<<endl;
}

int main(){
	solve();
	return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章