1. 程式人生 > >zoj3872 Beauty of Array (dp)

zoj3872 Beauty of Array (dp)

二次 sizeof name std () i++ 答案 ref code

題目鏈接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3872

題意:

給你n個數,求這n個數的連續子序列中不算重復的數的和,比如第二個樣例他的子序列就是{2},{2,3},{2,3,3},{3},{3,3},{3};但每個子序列中重復的元素不被算入,所以他們的總和就是2+5+5+3+3+3=21;

思路:

考慮到當前第i個數,對答案的貢獻是多少,dp[i]表示第i個數所做的貢獻

比如 1, 2, 3

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

1 dp[1] = 1;

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

2

1,2 dp[i] = dp[i-1]+a[i]*i = 1 + 2*2

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

3

2,3

12,3 dp[i] = dp[i-1]+a[i]*i = 5 + 3*3 紅色部分是dp[i-1], 對於第i個數的貢獻,只是把第i-1個數的貢獻,加上當前第i個數出現了幾次(i)

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

例如有序列1,2,3,4,5

若在末尾加入一個序列中沒有的數N,則新產生的子序列為:

N;

5,N;

4,5,N;

3,4,5,N;

2,3,4,5,N;

1,2,3,4,5,N;

則增加的輸出值為:

5;

4,5;

3,4,5;

2,3,4,5;

1,2,3,4,5;

的輸出值(dp[5])+6*N;

若在末尾加入一個序列中出現過的數字3,則新產生的子序列為:

3;

5,3;

4,5,3;

3,4,5,3

2,3,4,5,3

1,2,3,4,5,3

0,1,2,3,4,5,3

其中,最後四個子序列,因為末尾的3是第二次出現,故輸出值裏不將其計入,因此有效的子序列只有前面3個; dp[7] = dp[6]+7*a[7]-vis[a[7]]*a[7]; vis[a[i]]表示a[i]這個數最後出現的位置。

最終答案就是所有dp值加起來

代碼:

#include<bits/stdc++.h>
using
namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 1e5+10; int T; int vis[maxn*10]; ll dp[maxn],a[maxn]; int main(){ cin >> T; while(T--){ MS(vis); MS(dp); int n = read(); for(int i=1; i<=n; i++) a[i] = read(); ll ans = 0; for(int i=1; i<=n; i++){ dp[i] = dp[i-1] + (i-vis[a[i]])*a[i]; vis[a[i]] = i; ans += dp[i]; } cout << ans << endl; } return 0; }

zoj3872 Beauty of Array (dp)