HDU 4455 DP

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


你可能感兴趣的:(DP)