zoj3872 Beauty of Array (dp)

题目链接:

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;
}

 

posted @ 2017-07-29 20:34  _yxg123  阅读(138)  评论(0编辑  收藏  举报