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
1,2,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; }