Vijos 1901 學姐的錢包(線段樹優化dp)

2021-08-15 10:40:46 字數 1955 閱讀 9591

題目鏈結

分析:

學長講的線段樹例題

我們可以將錢數看做是乙個數軸

將一次交換看成數軸上的乙個線段:(r

[i]−

v[i]

) (r[

i]−v

[i])

那麼題目就可以視為帶權值的線段覆蓋問題

如果不帶權值,就是貪心的經典問題

而此問題我們需要用dp解決:

設計狀態:f[

i]f [i

]表示換成錢數

i i

的最小花費

我們把所有的線段按照右端點排序,順序轉移

因為每個線段一定是全部選擇,所以我們轉移右端點

對於線段[l

,r]' role="presentation" style="position: relative;">[l,

r][l

,r]f

[r]=

min(

f[k]

+v) f[r

]=mi

n(f[

k]+v

),其中

l<=

k<=

r l

<=

k<=

r我們每次進行轉移的時候,需要查詢乙個區間最小值,這個可以用線段樹維護

思路很簡單,但是在**實現的時候還是遇到了一些麻煩

首先我們在離散化的時候,只離散右端點即可

轉移的時候列舉每個線段

最後統計答案的時候:as

k(m,

max(

m,y)

) ask

(m,m

ax(m

,y))

#include

#include

#include

#include

#define ll long long

using

namespace

std;

const ll inf=1e18;

const

int n=100005;

int n,m,cnt,nn;

struct po;

po a[n];

int x[n<<1];

struct node;

node t[n<<2];

int cmp(const po &a,const po &b)

void insert(int bh,int l,int r,int x,ll z)

int mid=(l+r)>>1;

if (x<=mid) insert(bh<<1,l,mid,x,z);

else insert(bh<<1|1,mid+1,r,x,z);

t[bh].mn=min(t[bh<<1].mn,t[bh<<1|1].mn);

}ll ask(int bh,int l,int r,int l,int r)

int main()

x[++nn]=1; //dp初始值

sort(x+1,x+1+nn);

nn=unique(x+1,x+1+nn)-x-1;

build(1,1,nn);

sort(a+1,a+1+cnt,cmp);

for (int i=1;i<=cnt;i++)

printf("case #%d: ",cas);

ll ans=ask(1,1,nn,lower_bound(x+1,x+1+nn,m)-x,nn);

if (ans!=inf) printf("%d\n",ans);

else

printf("-1\n");

} return

0;}

vijos1901 學姐的錢包

學姐每次出門逛街都要帶恰好m元錢,不過她今天卻忘記帶錢包了.可憐的doc只好自己湊錢給學姐,但是他口袋裡只有一元錢.好在doc的n位朋友們都特別有錢,他們答應與doc作一些交換.其中第i位朋友說 如果doc有不少於ri元錢,doc可以把手上所有的錢都給這位朋友,並從這位朋友手中換回vi元錢,但是這次...

spfa vijos1901 學姐的錢包

學姐每次出門逛街都要帶恰好m元錢,不過她今天卻忘記帶錢包了.可憐的doc只好自己湊錢給學姐,但是他口袋裡只有一元錢.好在doc的n位朋友們都特別有錢,他們答應與doc作一些交換.其中第i位朋友說 如果doc有不少於ri元錢,doc可以把手上所有的錢都給這位朋友,並從這位朋友手中換回vi元錢,但是這次...

vijos1904 學姐的幸運數字

作者部落格 正解 搜尋 解題報告 考慮 操作而言,與乙個數的 至少會導致 1 的個數減半,因為乙個數和它的非的 1 顯然分布在不同位置,而我可以選擇把它和它的非操作的結果取個 min 容易發現,因為有 64 位,最多 7 次操作就能使得答案為 0 所以其實 n 7 的話就不用做了,那麼只有 n 6 ...