fork(1) download
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int x[1000002]; // 原数列
  5. int w[1000002]; // w[i]记录长度为i的后缀数列里面的unique元素的个数
  6. long long dp[1000002];
  7. int dp2[1000002]; // dp[i]记录有多少个元素的前一个相同元素的下标与该元素下标的差是i
  8.  
  9. int main()
  10. {
  11. int n,i,cc;
  12. while(scanf("%d",&n)&&n) // 输入数列长度
  13. {
  14. memset(dp,0,sizeof(dp)); // 此时dp[i]记录i这个元素出现的最大下标,初始化为0
  15. memset(dp2,0,sizeof(dp2));
  16. for(i=1;i<=n;i++)
  17. {
  18. scanf("%d",x+i); // 读取原数列第i个数
  19. dp2[i-dp[x[i]]]++; // 获取x[i]前一个相同元素的下标、做差、存进dp2
  20. dp[x[i]] = i; // 更新x[i]这个元素的最大下标,存进dp
  21. }
  22. cc = 0; // 记录后缀数组中unique元素的个数,初始化为0
  23. memset(dp,0,sizeof(dp)); // 重用dp数组,这里dp[i]记录的是i这个元素是否出现后缀数列中
  24. for(i=n;i>=1;i--) // 从n枚举到1
  25. {
  26. if(dp[x[i]]==0) cc++; // 如果x[i]未出现在后缀数组中,则增加cc
  27. dp[x[i]]=1; // 记录已出现在后缀数组中,存进dp
  28. w[n-i+1] = cc; // 长度为n-i+1的后缀中unique元素的个数,存进w
  29. }
  30. dp[1] = n; // 重用dp数组,这里dp[i]表示询问为i的时候的答案,当询问是1的时候,答案必然是n
  31. cc = n; // 重用cc,记录当前增量
  32. for(i=2;i<=n;i++) // 从2到n枚举
  33. {
  34. // 询问为i的结果可以由询问为i-1的结果递推
  35. dp[i] = dp[i-1] - w[i-1]; // 当询问为i-1的时候,最后一个区间无法添加新的数字,
  36. // 所以结果里面要减去长度为i-1的后缀数列里面的unique元素的个数
  37. cc -= dp2[i-1]; // 和前一个相同元素下标差为i-1的元素从这里开始不再存在增量
  38. dp[i] += cc; // 每个区间都多增加了一个元素,一共有cc个区间会增加一个新的unique元素
  39. }
  40. scanf("%d",&cc); // 以下为查询
  41. while(cc--)
  42. {
  43. scanf("%d",&i);
  44. printf("%I64d\n",dp[i]);
  45. }
  46. }
  47.  
  48. }
Success #stdin #stdout 0.03s 22216KB
stdin
7
1 1 2 3 4 4 5
3
1
2
3
0
stdout
                                                               7
                                                              10
                                                              12