题目链接:

E - BaoBao Loves Reading

 ZOJ - 4117 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

题目大意:有一个书架和桌子,桌子上最多放k本书,然后问你分别当k=i(1<=i<=n)时,顺序看书,如果当前桌子上有书的话,就不用从橱子上拿,如果当前的桌子上满了,会将上一次拿下来的数放上去,然后再取需要的书。然后问你分别当k=i(1<=i<=n)时,需要从书桌上取书多少次。

具体思路:dp[i]表示当k==i时,不需要从书橱上拿书的次数。然后计算答案的时候就是n-dp[i],代表需要从书橱上拿书的次数。

然后具体计算的时候,看这个样例   4 3 4 2 3 1 4 . 对于第二个4,我们判断这个4和上一次出现4的位置,这段范围内不同的数的个数是多少。对于4来说,这段区间不同的数的个数是2,也就是说当k>=2的时候,这个时候不需要再从书橱上拿书。但是当k<2的时候,是需要从书橱上拿书的。对于每一个位置,我们都这么处理,然后再对dp数组求一遍前缀和就可以了,因为当k==i的时候不需要从书橱上拿书的次数,当k>i的时候,也是肯定不需要拿的。

AC代码:

 1 #include<bits/stdc++.h>  2 using namespace std;  3 # define ll long long  4 # define inf 0x3f3f3f3f  5 const int maxn = 2e5+100;  6 int pre[maxn];  7 int tree[maxn];  8 int dp[maxn];  9 int n; 10 int lowbit(int t) 11 { 12 return t&-t; 13 } 14 void add(int x,int val) 15 { 16 while(x<=n) 17  { 18 tree[x]+=val; 19 x+=lowbit(x); 20  } 21 } 22 int ask(int x) 23 { 24 int sum=0; 25 while(x) 26  { 27 sum+=tree[x]; 28 x-=lowbit(x); 29  } 30 return sum; 31 } 32 void init() 33 { 34 for(int i=0; i<=n; i++) 35  { 36 pre[i]=0,tree[i]=0,dp[i]=0; 37  } 38 } 39 int main() 40 { 41 int T; 42 scanf("%d",&T); 43 while(T--) 44  { 45 int tmp; 46 scanf("%d",&n); 47  init(); 48 for(int i=1; i<=n; i++) 49  { 50 scanf("%d",&tmp); 51 if(pre[tmp]) 52  { 53 add(pre[tmp],-1); 54 add(i,1); 55 int len=ask(i)-ask(pre[tmp]-1); 56 dp[len]++; 57 pre[tmp]=i; 58  } 59 else 60  { 61 pre[tmp]=i; 62 add(pre[tmp],1); 63  } 64  } 65 for(int i=1; i<=n; i++) 66  { 67 dp[i]+=dp[i-1]; 68 if(i==1) 69 printf("%d",n-dp[i]); 70 else 71 printf(" %d",n-dp[i]); 72  } 73 printf("\n"); 74  } 75 return 0; 76 }

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄