题意 :
给你一个序列 , 查询 t ,问 序列 连续 长度为 t 的子区间 的不同数 的和
巧妙的动态规划
数据大, Dp可以 O(n)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> const int maxn = 1e6 +131; typedef long long ll; ll Dp[maxn]; ///总数 int Num[maxn]; /// 数列 int Suf[maxn]; /// 后 i 个数中不同的个数 int Flag[maxn]; /// 标记 数组 int Cnt[maxn]; /// 统计 两个相同的数 相间 i 有多少个。 int main() { int n, q; int tmp; while(~scanf("%d",&n) && n) { memset(Dp,0,sizeof(Dp)); memset(Suf,0,sizeof(Suf)); memset(Flag,0,sizeof(Flag)); memset(Cnt,0,sizeof(Cnt)); for(int i = 1; i <= n; ++i) { ///这里Flag数组标记Num【i】上一次出现的位置 scanf("%d",&Num[i]); Cnt[i-Flag[Num[i]]]++; /// Flag[Num[i]] = i; /// 更新位置 } memset(Flag,0,sizeof(Flag)); Suf[1] = Flag[Num[n]] = 1; /// 这里Flag数组标记 Num【i】 在后 K个中是否出现过 for(int i = 2; i <= n; ++i) /// 方便统计 Suf 数组 { if(Flag[Num[n-i+1]] == 0) { Flag[Num[n-i+1]] = 1; Suf[i] = Suf[i-1]+ 1; }else Suf[i] = Suf[i-1]; } int sum = n; Dp[1] = n; for(int i = 2; i <= n; ++i) { Dp[i] = Dp[i-1] - Suf[i-1]; /// Dp【i】 为 上一个 的总数 - 最后多出来的 Suf【i】 sum -= Cnt[i-1]; /// 然后 sum 减去 相距 i-1 的 重复次数, Dp[i] += sum; /// Dp【i】 有多个子区间, 再 加上 sum; } scanf("%d",&q); while(q--) { scanf("%d",&tmp); printf("%lld\n",Dp[tmp]); } } return 0; }
时间: 2024-10-29 19:10:54