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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值