vijosP1901学姐的钱包

题目:https://vijos.org/p/1901

题解:这题比较有意思。

经过一番思考之后我想出了下面的算法:

我们反着来推,按i从大到小

f[i]表示从>=m到 i 需要多长时间,则如果v[j]=i,则我们可以用f[i]+t[j] 去更新 r[j]-inf 的所有f值

由于f[i]是一个单调递减的函数,则我们只需要用它去更新r[j]-i-1即可

然后问题就变成了区间修改,单点查询,线段树即可

代码:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<iostream>
  7 #include<vector>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<string>
 12 #define inf 100000000000000ll
 13 #define maxn 250000
 14 #define maxm 500+100
 15 #define eps 1e-10
 16 #define ll long long
 17 #define pa pair<int,int>
 18 #define for0(i,n) for(int i=0;i<=(n);i++)
 19 #define for1(i,n) for(int i=1;i<=(n);i++)
 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 22 #define mod 1000000007
 23 using namespace std;
 24 inline int read()
 25 {
 26     int x=0,f=1;char ch=getchar();
 27     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 28     while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}
 29     return x*f;
 30 }
 31 int n,m,a[2*maxn],b[2*maxn],c[2*maxn];
 32 ll ti[maxn];
 33 struct seg{int k,l,r;ll mi,tag;}t[8*maxn];
 34 inline void build(int k,int l,int r)
 35 {
 36     t[k].l=l;t[k].r=r;int mid=(l+r)>>1;
 37     t[k].mi=inf;t[k].tag=inf;
 38     if(l==r)return;
 39     build(k<<1,l,mid);build(k<<1|1,mid+1,r);
 40 }
 41 inline void update(int k,ll z)
 42 {
 43     t[k].tag=min(t[k].tag,z);
 44     t[k].mi=min(t[k].mi,z);
 45 }
 46 inline void pushdown(int k)
 47 {
 48     if(t[k].tag==inf)return;
 49     update(k<<1,t[k].tag);
 50     update(k<<1|1,t[k].tag);
 51     t[k].tag=inf;
 52 }
 53 inline void pushup(int k)
 54 {
 55     t[k].mi=min(t[k<<1].mi,t[k<<1|1].mi);
 56 }
 57 inline void change(int k,int x,int y,ll z)
 58 {
 59     int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
 60     if(l==x&&r==y){update(k,z);return;}
 61     pushdown(k);
 62     if(y<=mid)change(k<<1,x,y,z);
 63     else if(x>mid)change(k<<1|1,x,y,z);
 64     else change(k<<1,x,mid,z),change(k<<1|1,mid+1,y,z);
 65     pushup(k);
 66 }
 67 inline ll query(int k,int x)
 68 {
 69     int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
 70     if(l==r)return t[k].mi;
 71     pushdown(k);
 72     if(x<=mid)return query(k<<1,x);else return query(k<<1|1,x);
 73 }
 74 inline bool cmp1(int x,int y){return a[x]<a[y];}
 75 inline bool cmp2(int x,int y){return b[x]>b[y];}
 76 int main()
 77 {
 78     freopen("input.txt","r",stdin);
 79     freopen("output.txt","w",stdout);
 80     int cs=read(),mm=0;
 81     while(cs--)
 82     {
 83         n=read();m=read();
 84         for1(i,n)a[i]=read(),a[n+i]=read(),ti[i]=read();a[2*n+1]=m;a[2*n+2]=1;
 85         for1(i,2*n+2)c[i]=i;
 86         sort(c+1,c+2*n+3,cmp1);
 87         int tot=0;
 88         for1(i,2*n+2)
 89         {
 90             if(i==1||a[c[i]]!=a[c[i-1]])tot++;
 91             b[c[i]]=tot;
 92         }
 93         for1(i,n)c[i]=i;
 94         sort(c+1,c+n+1,cmp2);
 95         build(1,1,tot);
 96         change(1,b[2*n+1],tot,0);
 97         for1(i,n)
 98         {
 99             ll x=query(1,b[c[i]]);if(x==inf)continue;
100             if(b[c[i]]>b[n+c[i]])change(1,b[n+c[i]],b[c[i]]-1,x+ti[c[i]]);
101         }
102         ll ans=query(1,b[2*n+2]);
103         printf("Case #%d: ",++mm);
104         if(ans==inf)printf("-1\n");else printf("%lld\n",ans);
105     }
106     return 0;
107 }

时间: 2024-08-02 13:00:11

vijosP1901学姐的钱包的相关文章

Vijos1901 学姐的钱包

描述 学姐每次出门逛街都要带恰好M元钱, 不过她今天却忘记带钱包了.可怜的doc只好自己凑钱给学姐, 但是他口袋里只有一元钱.好在doc的N位朋友们都特别有钱, 他们答应与doc作一些交换.其中第i位朋友说:如果doc有不少于Ri元钱,doc可以把手上所有的钱都给这位朋友,并从这位朋友手中换回Vi元钱,但是这次交换会浪费Ti的时间.doc希望可以在最短的时间内换到M元钱(其实是可以大于M的, 因为doc可以存私房钱呢), 否则学姐会生气的! 格式 输入格式 输入数据第一行给定T, 表示总的询问次

Vijos1901学姐的钱包

描述 学姐每次出门逛街都要带恰好M元钱, 不过她今天却忘记带钱包了.可怜的doc只好自己凑钱给学姐, 但是他口袋里只有一元钱.好在doc的N位朋友们都特别有钱, 他们答应与doc作一些交换.其中第i位朋友说:如果doc有不少于Ri元钱,doc可以把手上所有的钱都给这位朋友,并从这位朋友手中换回Vi元钱,但是这次交换会浪费Ti的时间.doc希望可以在最短的时间内换到M元钱(其实是可以大于M的, 因为doc可以存私房钱呢), 否则学姐会生气的! 格式 输入格式 输入数据第一行给定T, 表示总的询问次

2014.11.12模拟赛【美妙的数字】| vijos1904学姐的幸运数字

美妙的数字(number.c/.cpp/.pas) 题目描述 黄巨大认为非负整数是美妙的,并且它的数值越小就越美妙.当然0是最美妙的啦. 现在他得到一串非负整数,对于每个数都可以选择先对它做二进制非运算(模二意义下0.1互换,注意前导0也要交换),然后在任意相邻的两个数之间插入二进制与.二进制或,或者二进制异或.现在他想知道这样计算完产生的最美妙的数字是多少. 一共T组数据.对于每组数据,第一行一个n,表示这组数据中一串数有多少个.下面n个非负整数,表示这串数. 样例输入 2 2 3 6 3 1

卿学姐与魔法(优先队列)

个人心得:思路很简单,不过就是会超时,而且直接用数组的话肯定不够大. 所以就用优先队列,让里面只装N个数就好了,然后再次添加时进行比较,比他小就放进去. 不过这样超时,所以先将A,B排序,然后只要比队首大就break就可以过了. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<queue> 6 #include<

A - 卿学姐与公主(线段树+单点更新+区间极值)

A - 卿学姐与公主 Time Limit: 2000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 某日,百无聊赖的卿学姐打开了某11区的某魔幻游戏 在这个魔幻的游戏里,生活着一个美丽的公主,但现在公主被关押在了魔王的城堡中. 英勇的卿学姐拔出利刃冲向了拯救公主的道路. 走过了荒野,翻越了高山,跨过了大洋,卿学姐来到了魔王的第一道城关. 在这个城关面前的是魔王的精锐部队,这些士兵

qwb与学姐 (带秩并查集)

qwb与学姐 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 149  Solved: 54[Submit][Status][Web Board] Description qwb打算向学姐表白,可是学姐已经受够了他的骚扰,于是出了一个题想难住他:已知一幅n个点m条边的无向图,定义路径的值为这条路径上最短的边的长度,现在有 k个询问,询问从A点到B点的所有路径的值的最大值.qwb听完这个问题很绝望啊,聪明的你能帮帮他吗? Input 一组数据.第一行三

vijosP1903学姐的实习工资

描述 学姐去实习了, 一共实习了N天, 每一天都可以得到实习工资V[i], 这里V[1..N]被看作是整数序列.因为学姐很厉害, 所以V[1..N]是不下降的.也就是说学姐每天的工资只会越来越多, 不会变少.然而遗憾的是, 偷懒的学姐只记下来了其中M天的收入.第A[1]天获得了的工资为B[1].第A[2]天获得了的工资为B[2].第A[3]天获得了的工资为B[3]....第A[M]天获得了的工资为B[M].其中A[]是递增的.好在她记下来了第一天和第N天的收入. 也就是说A[1]=1, A[M]

qwb与学姐

qwb与学姐 Time Limit: 1 Sec  Memory Limit: 128 MB Description qwb打算向学姐表白,可是学姐已经受够了他的骚扰,于是出了一个题想难住他:已知一幅n个点m条边的无向图,定义路径的值为这条路径上最短的边的长度,现在有 k个询问,询问从A点到B点的所有路径的值的最大值.qwb听完这个问题很绝望啊,聪明的你能帮帮他吗? Input 一组数据.第一行三个整数n,m,k (1<=N<=50000,m<=200000,k<=100000).

hdu1344卿学姐种美丽的花

地址:http://acm.uestc.edu.cn/#/problem/show/1344 题目: 卿学姐种美丽的花 Time Limit: 8000/4000MS (Java/Others)     Memory Limit: 125535/65535KB (Java/Others) Submit Status 众所周知,在喵哈哈村,有一个温柔善良的卿学姐. 卿学姐喜欢和她一样美丽的花.所以卿学姐家的后院有很多的花坛. 卿学姐有nn个花坛,一开始第ii个花坛里有A[i]A[i]朵花.每过一段