题意:这个题给你n个数,然后有q组询问,无修改,每次询问一个长度x,问你所有长度为x的区间价值加和是多少,区间的价值的计算是这样定义的,一个区间的价值就等于这个区间中不同数字的个数
思路:看了题解虽然理解了,但感觉还是很难想啊,原本这个题卡在了怎么把n2的降维成n的,这个题目也算是很经典的一个套路吧,疯狂预处理,把所需要的信息不断转化,疯狂降维预处理,然后达到On递推,感觉对于dp[i]和dp[i-1]之间的关系,单点贡献的那一部分不怎么容易想到,而且想到了单点贡献,也想不到怎么预处理,QAQ
附传送门一只
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e6+7; int n; int a[maxn],cnt[maxn]; LL dp[maxn],vis[maxn]; int main() { while(~scanf("%d",&n),n){ for(int i=1;i<=n;i++)scanf("%d",&a[i]); int res=0; memset(dp,0,sizeof(dp)); for(int i=n;i>=1;i--){ if(!dp[a[i]])dp[a[i]]=1,res++; cnt[n-i+1]=res; } memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ dp[i]=vis[a[i]]; vis[a[i]]=i; } memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ vis[i-dp[i]]++; } vis[n+1]=0; for(int i=n;i>=1;i--)vis[i]+=vis[i+1]; dp[1]=n; for(int i=2;i<=n;i++){ dp[i]=dp[i-1]-cnt[i-1]+vis[i]; } int q; scanf("%d",&q); while(q--){ int x; scanf("%d",&x); printf("%lld ",dp[x]); } } return 0; }