练习题

背包(2020-06-14)

集排序,贪心,前缀和,二分的很综合的题

题目描述

Applese有1个容量为v的背包,有n个物品,每一个物品有一个价值ai,以及一个大小bi
然后他对此提出了自己的疑问,如果我不要装的物品装的价值最大,只是一定需要装m个物品,要使得求出来的物品价值的中位数最大
Applese觉得这个题依然太菜,于是他把这个问题丢给了你
当物品数量为偶数时,中位数即中间两个物品的价值的平均值

输入描述:

第一行三个数v, n, m,分别代表背包容量,物品数量以及需要取出的物品数量
接下来n行,每行两个数ai,bi,分别代表物品价值以及大小
n ≤ 1e5, 1 ≤ m ≤ n, ai ≤ 1e9, v ≤ 1e9, bi ≤ v

输出描述:

仅一行,代表最大的中位数
示例1

输入

20 5 3
3 5
5 6
8 7
10 6
15 10

输出

8
m为奇数的情况下
然后我们枚举每个位置,如果该位置是中位数的最大,那么这个位置前面选m/2个的重量加上后面m/2个重量,使他们小于V就说明这个位置可以取得的,只需要维护一个大小为m/2 的堆就行,每次pop掉堆中最大的
m为偶数的时候同理
但是中间需要选择两个位置,数据范围为1e5,n^2肯定不行,所以用nlogn的算法,可以枚举第一个位置,二分第二个位置
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int x=0;char c=getchar();
 6     for(;!isdigit(c);c=getchar());
 7     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
 8     return x;
 9 }
10 long long v,n,m;
11 long long ans=-1;
12 long long sum[100005][2];
13 priority_queue<long long> q;
14 struct node
15 {
16     long long a;
17     long long b;
18 }p[100005];
19 inline bool cmp(node x,node y)
20 {
21     return x.a<y.a;
22 }
23 int main()
24 {
25     cin>>v>>n>>m;
26     for(int i=1;i<=n;i++)
27     {
28         scanf("%lld%lld",&p[i].a,&p[i].b);
29     }
30     sort(p+1,p+n+1,cmp);
31     if(m&1)
32     {
33         for(int i=1;i<=n;i++)
34         {
35             sum[i][0]=sum[i-1][0]+p[i].b; q.push(p[i].b);
36             if(q.size()>m/2)
37             {
38                 sum[i][0]-=q.top();
39                 q.pop();
40             }
41         }
42         while(!q.empty()) q.pop();
43         for(int i=n;i>=1;i--)
44         {
45             sum[i][1]=sum[i+1][1]+p[i].b; q.push(p[i].b);
46             if(q.size()>m/2)
47             {
48                 sum[i][1]-=q.top();
49                 q.pop();
50             }
51         }
52         for(int i=m/2+1;i<=n-m/2;i++)
53         {
54             if(sum[i-1][0]+p[i].b+sum[i+1][1]<=v)
55             ans = max(ans, p[i].a);
56         }
57         printf("%lld\n",ans);
58     }
59     else
60     {
61         for(int i=1;i<=n;i++)
62         {
63             sum[i][0]=sum[i-1][0]+p[i].b; q.push(p[i].b);
64             if(q.size()>m/2-1)
65             {
66                 sum[i][0]-=q.top();
67                 q.pop();
68             }
69         }
70         while(!q.empty()) q.pop();
71         for(int i=n;i>=1;i--)
72         {
73             sum[i][1]=sum[i+1][1]+p[i].b; q.push(p[i].b);
74             if(q.size()>m/2-1)
75             {
76                 sum[i][1]-=q.top();
77                 q.pop();
78             }
79         }
80         for(int i=m/2;i<=n-m/2;i++)  //枚举左中位数
81         {
82             int le=i+1;int ri=n-m/2+1;
83             while(le<=ri)
84             {
85                 int mid=le+ri>>1;
86                 if(sum[i-1][0]+p[i].b+p[mid].b+sum[mid+1][1]<=v)
87                 {
88                     ans=max(ans,p[i].a+p[mid].a>>1);
89                     le=mid+1;
90                 }
91                 else ri=mid-1;
92             }
93         }
94         printf("%lld\n",ans);
95     }
96     return 0;
97 }
View Code
小A的最短路

题目描述

小A这次来到一个景区去旅游,景区里面有N个景点,景点之间有N-1条路径。小A从当前的一个景点移动到下一个景点需要消耗一点的体力值。但是景区里面有两个景点比较特殊,它们之间是可以直接坐观光缆车通过,不需要消耗体力值。而小A不想走太多的路,所以他希望你能够告诉它,从当前的位置出发到他想要去的那个地方,他最少要消耗的体力值是多少。

输入描述:

第一行一个整数N代表景区的个数。
接下来N-1行每行两个整数u,v代表从位置u到v之间有一条路径可以互相到达。
接下来的一行两个整数U,V表示这两个城市之间可以直接坐缆车到达。
接下来一行一个整数Q,表示有Q次询问。
接下来的Q行每行两个整数x,y,代表小A的位置在x,而他想要去的地方是y。

输出描述:

对于每个询问下x,y输出一个结果,代表x到y消耗的最少体力对于每个询问下x,y输出一个结果,代表x到y消耗的最少体力x,yxy
示例1

输入

4
1 2
1 3
2 4
3 4
2
1 3
3 4

输出

1
0

备注:

1≤N≤3e5, 1≤Q≤1e6

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int x=0;char c=getchar();
 6     for(;!isdigit(c);c=getchar());
 7     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
 8     return x;
 9 }
10 #define N 300005
11 int n,tot=0;
12 int nex[N<<1],head[N],to[N<<1];
13 int size[N],d[N],fa[N],son[N],top[N];
14 inline void add(int u,int v)
15 {
16     nex[++tot]=head[u];
17     head[u]=tot;
18     to[tot]=v;
19 }
20 inline void dfs1(int u,int fat)
21 {
22     size[u]=1;
23     for(int i=head[u];i;i=nex[i])
24     {
25         int v=to[i];
26         if(v==fat) continue;
27         fa[v]=u;
28         d[v]=d[u]+1;
29         dfs1(v,u);
30         size[u]+=size[v];
31         if(size[v]>size[son[u]]) son[u]=v;
32     }
33 }
34 inline void dfs2(int u,int tp)
35 {
36     top[u]=tp;
37     if(!son[u]) return;
38     dfs2(son[u],tp);
39     for(int i=head[u];i;i=nex[i])
40     {
41         int v=to[i];
42         if(v==fa[u]||v==son[u]) continue;
43         dfs2(v,v); 
44     }
45 }
46 inline int LCA(int u,int v)
47 {
48     while(top[u]!=top[v])
49     {
50         if(d[top[u]]<d[top[v]]) v=fa[top[v]];
51         else u=fa[top[u]];
52     }
53     if(d[u]>d[v]) return v;
54     else return u; 
55 }
56 int main()
57 {
58     n=read();
59     for(int i=1;i<n;i++)
60     {
61         int u=read(),v=read();
62         add(u,v);
63     }
64     d[1]=1;
65     dfs1(1,-1);
66     dfs2(1,1);
67     int U=read(),V=read();
68     int q=read();
69     int lcaxy,lcaxu,lcaxv,lcayu,lcayv;
70     while(q--)
71     {
72         int ans=0;
73         int x=read(),y=read();
74         lcaxy=LCA(x,y);lcaxu=LCA(x,U);lcaxv=LCA(x,V);lcayu=LCA(y,U);lcayv=LCA(y,V);
75         ans=min(d[x]-d[lcaxy]*2+d[y],(d[x]-d[lcaxu]*2+d[U])+(d[V]-d[lcayv]*2+d[y]));
76         ans=min(ans,(d[x]-d[lcaxv]*2+d[V])+(d[U]-d[lcayu]*2+d[y]));
77         //cout<<"topx="<<top[x]<<" dx="<<d[x]<<" topy="<<top[y]<<" dy="<<d[y]<<" top1="<<top[1]<<endl;
78         //cout<<"lca(x,y)="<<lcaxy<<endl;
79         printf("%d\n",ans);
80     }
81     return 0;
82 }
View Code

 


posted @ 2020-06-14 15:05  SuYongkang  阅读(162)  评论(0)    收藏  举报