tyvj P4751 NOIP春季系列課程 H's Problem
-H‘s Problem-
描述
小H是一個喜歡逛街的女孩子,但是由於上了大學,DDL越來越多了,她不能一直都處於逛街的狀態。為了讓自己能夠更加沈迷於學習,她規定一次逛街只逛T個單位的時間。
小H從1號店出發,從1號店走到第i號店需要花費ai的時間,這些店形成了一條直線,也就是說小H從第i號店走到第i+1號店需要花費的時間為a{i+1}-ai。若小H選擇了第i號店並且進去逛,則會消耗bi的時間。對於第i家店,小H都對它有自己的看法。具體地,可以用ci來表示小H是否喜歡這家店。如果ci=1,則表示小H喜歡i號店,否則若ci=0,則表示小H不喜歡這家店。
小H想盡可能逛更多的店,但是她也有屬於自己的目標,也就是說逛至少k家喜歡的店,在這個基礎上,能逛的店越多越好。
小H現在想知道自己最多能逛多少店,當然若小H無論如何也逛不到k家喜歡的店,那麽你輸出-1就行了。
輸入格式
第一行3個數n,T,k。
接下來一行n個數表示ai。
接下來一行n個數表示bi。
接下來一行n個數表示ci。
輸出格式
輸出一個數表示答案。
輸入樣例
4 11 1
0 1 2 10
1 1 1 1
0 0 0 1
輸出樣例
1
數據範圍
對於20%的數據n<=20。
對於40%的數據n<=1000。
對於100%的數據n<=100000,1<=T<=10^9,0<=k<=n,a1=0,a1<a2<…<an<=10^9,1<=bi<=10^9,0<=ci<=1,數據有梯度。
一道蠻有趣的數據結構題;
先分析下題意,我們要求的是在 1~n 中選擇盡量多的店去逛,同時至少逛k家我們喜歡的店;
因為到每家店所需時間不同,我們走的越遠,剩余逛店時間就越少,但可選擇的店會增多,所以答案上不具備單調性,只能枚舉每一個點作為終點,然後分別求答案數;
對於任意一點 i 作為終點求答案數,實際就是在 1~i 中選擇盡量多的點,即求一個動態升序數組的前 x 項,使它們的和 <= T-a[i];
我們註意到元素的插入順序和元素大小都是已知的,因此可以通過離散化 + 排序,預處理出所有元素在數組中應在的位置,然後構建一個靜態數組,將元素按順序放進它應在的位置,這樣較動態維護快出很多;
因為數組中元素有序,所以我們求前綴和即可;
對一個動態數組進行單點修改和求前綴和,很明顯可以使用樹狀數組(當然線段樹也可);
樹狀數組中下標代表元素大小(離散化後),每個節點存儲元素個數及元素權值和(離散化前);
前綴和是連續的,因此可以對下標進行二分查找;
最後對於必須逛夠 k 家喜歡的店的問題,因為只需選擇 1~i 中前 k 家耗時最少的店,我們可以維護一個大根堆,存儲前 k 小的 k 個元素,從堆中踢出或未進堆元素則存入樹狀數組;
復雜度方面,枚舉終點 O(n),排序 + 離散化 O(n*logn),二分 + 樹狀數組查詢(修改) O(logn*logn),堆維護 O(logn),總復雜度 O(n*logn*logn);
(實際上還可以用平衡樹做,復雜度貌似可以降至 O(n*logn)
AC GET☆DAZE(大概
↓代碼(只有70分,希望dalao們能幫我挑挑錯(堆寫的很惡心orz
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<vector> 7 #define ll long long 8 #define MAX_L 0x7fffffff7fffffff 9 using namespace std; 10 struct mk 11 { 12 ll c,r; 13 }; 14 struct poi 15 { 16 ll n,s; 17 }; 18 mk shop[100039]; 19 poi tree[100039]={0}; 20 ll rou[100039],tim[100039],ord[100039],hea[100039]={0},size=0,n,sum,calcs; 21 bool kn[100039]={0}; 22 bool cmp(mk a,mk b) 23 { 24 return a.c<b.c; 25 } 26 void ueni() 27 { 28 ll a=size,key=hea[size]; 29 while(1) 30 { 31 if(tim[hea[a/2]]<tim[key]) 32 { 33 hea[a]=hea[a/2]; 34 a/=2; 35 } 36 else 37 { 38 hea[a]=key; 39 return; 40 } 41 } 42 } 43 void sitani() 44 { 45 ll a=1,key=hea[1],ne; 46 while(1) 47 { 48 ne=a*2; 49 if(tim[hea[a*2]]<tim[hea[a*2+1]]) 50 { 51 ne++; 52 } 53 if(a*2>size) 54 { 55 hea[a]=key; 56 return; 57 } 58 if(tim[hea[ne]]>tim[key]) 59 { 60 hea[a]=hea[ne]; 61 a=ne; 62 } 63 else 64 { 65 hea[a]=key; 66 return; 67 } 68 } 69 } 70 ll lowbit(ll k) 71 { 72 return -k&k; 73 } 74 void maketree(ll x) 75 { 76 ll a=ord[x]; 77 while(a<=n) 78 { 79 tree[a].n+=tim[x]; 80 tree[a].s++; 81 a+=lowbit(a); 82 } 83 return; 84 } 85 ll calctree(ll x) 86 { 87 ll calcn=0,a=x; 88 calcs=0; 89 while(a) 90 { 91 calcn+=tree[a].n; 92 calcs+=tree[a].s; 93 a-=lowbit(a); 94 } 95 return calcn; 96 } 97 int main() 98 { 99 mk stp; 100 ll T,k,t,l,r,m,ans=-1,a,b,c; 101 scanf("%lld%lld%lld",&n,&T,&k); 102 for(a=1;a<=n;a++) 103 { 104 scanf("%lld",&rou[a]); 105 } 106 for(a=1;a<=n;a++) 107 { 108 scanf("%lld",&tim[a]); 109 stp.c=tim[a]; 110 stp.r=a; 111 shop[a]=stp; 112 } 113 for(a=1;a<=n;a++) 114 { 115 scanf("%lld",&kn[a]); 116 } 117 sort(shop+1,shop+n+1,cmp); 118 for(a=1;a<=n;a++) 119 { 120 ord[shop[a].r]=a; 121 } 122 tim[0]=MAX_L; 123 for(a=1;a<=n;a++) 124 { 125 if(kn[a]) 126 { 127 if(size<k) 128 { 129 T-=tim[a]; 130 hea[++size]=a; 131 ueni(); 132 } 133 else 134 { 135 if(hea[1]!=0 && tim[a]<tim[hea[1]]) 136 { 137 T-=tim[a]; 138 T+=tim[hea[1]]; 139 maketree(hea[1]); 140 hea[1]=a; 141 sitani(); 142 } 143 else 144 { 145 maketree(a); 146 } 147 } 148 } 149 else 150 { 151 maketree(a); 152 } 153 t=T-rou[a]; 154 if(size==k && t>=0) 155 { 156 l=1,r=n; 157 while(l+39<r) 158 { 159 m=(l+r)>>1; 160 if(calctree(m)<=t) 161 { 162 l=m; 163 } 164 else 165 { 166 r=m; 167 } 168 } 169 while(calctree(l)<=t && l<=n) 170 { 171 l++; 172 sum=calcs; 173 } 174 ans=max(ans,sum+k); 175 } 176 } 177 printf("%lld",ans); 178 return 0; 179 }View Code
tyvj P4751 NOIP春季系列課程 H's Problem