BZOJ2131免费的馅饼 DP+树状数组
免費(fèi)的餡餅
Description
Input
第一行是用空格隔開(kāi)的二個(gè)正整數(shù),分別給出了舞臺(tái)的寬度W(1到10^8之間)和餡餅的個(gè)數(shù)n(1到10^5)。 接下來(lái)n行,每一行給出了一塊餡餅的信息。由三個(gè)正整數(shù)組成,分別表示了每個(gè)餡餅落到舞臺(tái)上的時(shí)刻t[i](1到10^8秒),掉到舞臺(tái)上的格子的編號(hào)p[i](1和w之間),以及分值v[i](1到1000之間)。游戲開(kāi)始時(shí)刻為0。輸入文件中同一行相鄰兩項(xiàng)之間用一個(gè)空格隔開(kāi)。輸入數(shù)據(jù)中可能存在兩個(gè)餡餅的t[i]和p[i]都一樣。
Output
一個(gè)數(shù),表示游戲者獲得的最大總得分。
Sample Input
3 4
1 2 3
5 2 3
6 3 4
1 1 5
Sample Output
12
【數(shù)據(jù)規(guī)模】
對(duì)于100%的數(shù)據(jù),1<=w,t[i]<=10^8,1<=n<=100000。
題解:
用f[i][j]表示游戲者在第i時(shí)刻,第j位置上獲得的最大價(jià)值,考慮將餡餅按時(shí)間從小到大排序,這樣可以將二維數(shù)組降到一維,用f[i]表示到第i個(gè)餡餅,第i個(gè)必須選的最大值,然后枚舉 i 到 i-1 所有的 j,如果它接到a[j]這個(gè)餡餅以后能在規(guī)定時(shí)間內(nèi)跑到a[i],就用f[j]來(lái)更新f[i]。
考慮什么樣的 j 能作為決策點(diǎn),對(duì)于當(dāng)前點(diǎn)的a【i】和用作決策點(diǎn)的a【j】,時(shí)間限制是 a[i].t - a[j].t,它們之間的距離是abs(a[i].pos-a[j].pos);跑過(guò)這段距離最少所需要的時(shí)間是。注意這里是向上取整,因?yàn)槿绻?個(gè)格子的話它要用3個(gè)單位時(shí)間跑到而不是2個(gè)。
那么如果j可以作為i的決策點(diǎn)就可以列出一個(gè)不等式。為了消掉難搞的絕對(duì)值我們分兩種情況討論:
①當(dāng)i的pos大于j的pos的時(shí)候,就是 。把i的和j的分別拿到兩邊去。乘以2消掉上取整,然后再移項(xiàng)就有了一個(gè)非常好的式子:。
②當(dāng)i的pos小于j的pos的時(shí)候,我們可以化出式子:。于是就可以給每一個(gè)a[i]預(yù)處理兩個(gè)權(quán)值,轉(zhuǎn)化比較w1或w2就可以了。但是這個(gè)玩意怎么優(yōu)化呢?如果直接這么看的話它的限制好像還是很多,還是沒(méi)有辦法搞。
當(dāng)i的pos大于j的pos并且i的w1大于j的w1的時(shí)候,把w1加上兩倍的pos就變成了w2,這個(gè)時(shí)候相當(dāng)于是大的那一邊加上較大的數(shù)字,小的那一邊加上較小的數(shù)字,大小關(guān)系不變;當(dāng)i的pos小于j的pos的時(shí)候證明方法是類似的。用后面的式子推出前面的那就很顯然了。
那么只需要把所有餡餅按照w1為第一關(guān)鍵字,w2為第二關(guān)鍵字排序,然后用樹(shù)狀數(shù)組維護(hù)前綴最大值就可以了。注意作為下標(biāo)的w2要離散化。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1e5+10; int w,n;//舞臺(tái)的寬度W(1到10^8之間)和餡餅的個(gè)數(shù)n(1到10^5) int cnt;//數(shù)據(jù)量 int ans;//答案 int f[maxn]; int Hash[maxn]; int s[maxn];//樹(shù)狀數(shù)組struct pies {int t;//餡餅落到舞臺(tái)上的時(shí)刻t[i](1到10^8秒)int p;//掉到舞臺(tái)上的格子的編號(hào)p[i](1和w之間)int v;//以及分值v[i](1到1000之間)int w1;//w1=2*t+posint w2;//w2=2?t?pos }; pies a[maxn]; void init() {cnt=0;ans=0;memset(f,0,sizeof(f));memset(Hash,0,sizeof(Hash));memset(s,0,sizeof(s));memset(a,0,sizeof(a)); } bool comp(pies a,pies b) {return a.w1<b.w1||a.w1==b.w1&&a.w2<=b.w2; } int lowbit(int x) {return x&(-x); } int ask(int i) {int Max=0;while(i){Max=max(Max,s[i]);i-=lowbit(i);}return Max; } void add(int i,int val) {while(i<=cnt){s[i]=max(s[i],val);i+=lowbit(i);} } int main() { //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout);while (scanf("%d%d",&w,&n)!=EOF){init();for(int i=1;i<=n;i++){scanf("%d%d%d",&a[i].t,&a[i].p,&a[i].v);a[i].t*=2;a[i].w1=a[i].t-a[i].p;a[i].w2=a[i].t+a[i].p;Hash[++cnt]=a[i].w2;}sort(Hash+1,Hash+cnt+1);cnt=unique(Hash+1,Hash+cnt+1)-Hash-1;for(int i=1;i<=n;i++)a[i].w2=lower_bound(Hash+1,Hash+cnt+1,a[i].w2)-Hash;sort(a+1,a+n+1,comp);for(int i=1;i<=n;i++){f[i]=ask(a[i].w2)+a[i].v;ans=max(ans,f[i]);add(a[i].w2,f[i]);}printf("%d\n",ans); }return 0; }?
總結(jié)
以上是生活随笔為你收集整理的BZOJ2131免费的馅饼 DP+树状数组的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Easy Multiplication
- 下一篇: HDU1166 敌兵布阵 单点更新