看到还没有题解,那就来一发 相对于说这题是dp,我觉得更像是体现了数组预处理信息的一种递推,很巧妙的运用数组储存信息
- 由数据范围知肯定要提前预处理,时间复杂度为O(n),那么容易想到每个区间存在关联,比如f[4]比f[3]多了一个数,贡献在于f[3]中是否有此多出的数,转化一下问题 f【4】新增的数到之前最近出现位置的距离是否>=4,若大于则有贡献1,可推广到整个区间上的所有子区间
- 下面转移方程f[i]=f[i-1]+cnt[i]-diff[i-1],cnt[i]代表距离>=i的满足个数,因为整个区间包含多个所要更新的子区间,而总贡献即为cnt【i】,之前我们要先处理last[i]数组,为距离数组,diff[i]是一个后缀数组,为增大区间后少掉的那个区间
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+8;
int n,q,a[N],last[N],diff[N],dp[N],x,cnt[N],cnt1[N];
int mp[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
last[i]=i-mp[a[i]];
mp[a[i]]=i;
}
for(int i=1;i<=n;i++)cnt[last[i]]++;
for(int i=n;i>=1;i--){
cnt[i-1]+=cnt[i];
}
memset(mp,0,sizeof(mp));
int sum=0;
for(int i=n;i>=1;i--){
if(!mp[a[i]]){
sum++;
mp[a[i]]++;
}
diff[n-i+1]=sum;
}
dp[1]=n;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1]+cnt[i]-diff[i-1];
}
scanf("%d",&q);
while(q--){
scanf("%d",&x);
printf("%d\n",dp[x]);
}
return 0;
}