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