2012 Asia Hangzhou Regional Contest
给定一个整数串,有Q组询问,问这个串中长度为W的子串中不同的数字之和为多少。
DP思路预处理出来所有长度的答案
dp[i]=dp[i-1]-sum[n-i+2]+cnt; 长度为i的答案=长度为i-1的答案-末尾为最后一位的长度为i-1的子串的不同数字数+cnt为任意元素与上一个出现的位置距离>=i的个数
cnt-=mark[i-1]; cnt-=任意元素与上一个出现的位置距离为i-1的个数
sum和mark数组可以预处理得到
#include "stdio.h"
#include "string.h"
int hash[1000010],mark[1000010],a[1000010],sum[1000010];
__int64 dp[1000010];
int main()
{
int n,i,cnt,m,x;
while (scanf("%d",&n)!=EOF)
{
if (n==0) break;
memset(hash,0,sizeof(hash)); // 记录i数字上一个出现的位置
memset(mark,0,sizeof(mark)); // 记录任意元素与上一个出现的位置距离为i的个数
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
mark[i-hash[a[i]]]++;
hash[a[i]]=i;
}
memset(hash,0,sizeof(hash)); // 记录i数字是否出现过
sum[n]=1;
hash[a[n]]=1;
for (i=n-1;i>=1;i--)
if (hash[a[i]]==0)
{
hash[a[i]]=1;
sum[i]=sum[i+1]+1;
}
else
sum[i]=sum[i+1];
dp[1]=n;
cnt=n;
for (i=2;i<=n;i++)
{
dp[i]=dp[i-1]-sum[n-i+2];
cnt-=mark[i-1];
dp[i]+=cnt;
}
scanf("%d",&m);
while (m--)
{
scanf("%d",&x);
printf("%I64d\n",dp[x]);
}
}
return 0;
}