hdu 4455 dp

题目大意:给定一个数组,求长度为x的字串中不同的数字的总数。

发现看别人的思路做的题写完之后等若干天之后还是想不懂怎么写。。。前几天一直在看后缀数组,ac自动机什么问题的,竟然将这题往后缀自动机那里想了。。。。然后发现实在是想不出来怎么写,然后发现了自己以前写的代码,然后就对自己真的无语了,周四就要去成都参加区域赛,这样的状态是真的让人很无语啊。。。

解题思路

对于长度为i的字串得出的结果为ans[i],那么对于ans[i+1]等于每个长度i的字串后面加上一个数,然后减去数组的最后的一个长度为i的字串的值。对于数组可以先进行处理,ans[i+1]=ans[i]+cont[i]-pp[n-i+2],cont[i]代表对于一个数,其前面的与它自己相等的数的距离大于等于i的,pp数组记录的是后面将要处理的值,然后就可以了

下面是代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<climits>
#include<map>
using namespace std;

#define rep(i,n) for(int i=0; i<n; i++)
#define repf(i,n,m) for(int i=(n); i<=(m); ++i)
#define repd(i,n,m) for(int i=(n); i>=(m); --i) 
#define ll long long
#define arc(a) ((a)*(a))
#define inf 100000
#define exp 0.000001
#define N  1000006
int a[N];
ll ans[N];
int pre[N];
ll cont[N];
bool vis[N];
ll pp[N];
int n;

int main()
{ 
	while(scanf("%d",&n) && n)
	{
		repf(i,1,n) scanf("%d",&a[i]);
        memset(pre,-1,sizeof(pre));
		memset(cont,0,sizeof(cont));
        memset(vis,false,sizeof(vis));
		memset(pp,0,sizeof(pp));
		repf(i,1,n)
		{
			if(pre[a[i]]!=-1)
				cont[i-pre[a[i]]]++;
			else
				cont[i]++;
			pre[a[i]]=i;
		}
		repd(i,n-1,1) cont[i]+=cont[i+1];
		pp[n+1]=0;
        repd(i,n,1)
			if(vis[a[i]]==false)
				pp[i]=pp[i+1]+1,
					vis[a[i]]=true;
			else 
				pp[i]=pp[i+1];
		ans[1]=n;
        repf(i,2,n)
			ans[i]=ans[i-1]+cont[i]-pp[n-i+2];
		int m,x;
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d",&x);
			cout<<ans[x]<<endl;
		}
	}

   return 0;
}
  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡定的小Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值