今天刷 堆

2879 堆的判断

时间限制: 1 s    空间限制: 32000 KB    题目等级 : 黄金 Gold
题目描述 Description

堆是一种常用的数据结构。二叉堆是一个特殊的二叉树,他的父亲节点比两个儿子节点要大,且他的左右子树也是二叉堆。现在输入一颗树(用二叉树的数组表示,即a[i]的左儿子与右儿子分别为a[2i],a[2i+1]),要求判断他是否是一个堆。

输入描述 Input Description

一个整数N,表示结点数。

第二行N个整数,表示每个结点代表的数字

输出描述 Output Description

如果是,输出‘Yes’

否则输出‘No’

样例输入 Sample Input

5

1 2 3 4 5

样例输出 Sample Output

No

数据范围及提示 Data Size & Hint

1<N<100

数字在2^31以内

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 int a[110],n;
 6 int main()
 7 {
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;i++)
10       scanf("%d",&a[i]);
11     for(int i=1;i<=n;i++)
12     {
13         if(i*2<=n){
14             if(a[i*2]>=a[i]){
15                 printf("No
");return 0;
16             }
17         }
18         if(i*2+1<=n){
19             if(a[i*2+1]>=a[i]){
20                 printf("No
");return 0;
21             }
22         }
23     }
24     printf("Yes
");
25     return 0;
26 }

3110 二叉堆练习3

时间限制: 3 s    空间限制: 128000 KB    题目等级 : 黄金 Gold

题目描述 Description

给定N(N≤500,000)和N个整数(较有序),将其排序后输出。

输入描述 Input Description

N和N个整数

输出描述 Output Description

N个整数(升序)

样例输入 Sample Input

5

12 11 10 8 9

样例输出 Sample Output

8 9 10 11 12

数据范围及提示 Data Size & Hint

对于33%的数据 N≤10000

对于另外33%的数据 N≤100,000  0≤每个数≤1000

对于100%的数据 N≤500,000  0≤每个数≤2*10^9

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,t,a;
 5 int heap[500010];
 6 void heap_up(int now){
 7     if(now<=1) return;
 8     int top=now/2;
 9     if(heap[now]<heap[top])
10      {
11          swap(heap[now],heap[top]);
12          heap_up(top);
13      }
14 }
15 void heap_down(int now){
16     if(now>n) return;
17     int lc,rc,next=now;
18     bool blc,brc;
19     if((now*2)<=n) blc=true,lc=heap[now*2];
20     else blc=false;
21     if((now*2| 1)<=n) brc=true,rc=heap[now*2| 1];
22     else brc=false;
23     if(blc){
24         if(heap[next]>lc)
25           next=now<<1;
26     }
27     if(brc){
28         if(heap[next]>rc)
29           next=now << 1 | 1;
30     }
31     if(next!=now){
32         swap(heap[next],heap[now]);
33         heap_down(next);
34     }
35 }
36 void heap_pop(){
37     heap[1]=heap[n];
38     n--;
39     heap_down(1);
40 }
41 void make_heap(int x){
42     t++;
43     heap[t]=x;
44     heap_up(t);
45 }
46 int main()
47 {
48     scanf("%d",&n);
49     int m=n;
50     for(int i=1;i<=n;i++)
51     {
52         scanf("%d",&a);
53         make_heap(a);
54     }
55     for(int i=1;i<=m;i++)
56     {
57         printf("%d ",heap[1]);
58         heap_pop();
59     }
60     return 0;
61 }// 手写堆
 1 // make_heap
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 unsigned long long a[1000000+20];
 5 int main() {
 6     int n;
 7     cin >> n;
 8     for(int i = 1; i <= n; i++) {
 9       scanf("%d", &a[i]);
10     }
11     make_heap(a + 1, a + n + 1);
12     sort_heap(a + 1, a + n + 1);
13     for(int i = 1; i <= n; i++) {
14       printf("%d ", a[i]);
15     }
16     return 0;
17 }
 1 // sort
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 int n,a[500010];
 8 int main()
 9 {
10     scanf("%d",&n);
11     for(int i=1;i<=n;i++)
12       scanf("%d",&a[i]);
13     sort(a+1,a+n+1);
14     for(int i=1;i<=n;i++)
15       printf("%d ",a[i]);
16     return 0;
17 }

时空如图:

三次分别是 make_heap/手敲堆/sort。。。。。

1063 合并果子

2004年NOIP全国联赛普及组

 时间限制: 1 s    空间限制: 128000 KB    题目等级 : 钻石 Diamond
题目描述 Description

  在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。


    每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。


    因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。


    例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。

输入描述 Input Description

 输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。

输出描述 Output Description

输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。

样例输入 Sample Input


1 2 9

样例输出 Sample Output

15

数据范围及提示 Data Size & Hint

对于30%的数据,保证有n<=1000: 
对于50%的数据,保证有n<=5000; 
对于全部的数据,保证有n<=10000。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 using namespace std;
 5 priority_queue <int> que;
 6 int main()
 7 {
 8     int n,x;
 9     scanf("%d",&n);
10     for(int i=1;i<=n;i++)
11       scanf("%d",&x),que.push(-x);
12     int ans=0;
13     for(int i=1,tmp;i<n;i++)
14     {
15         tmp=que.top();
16         ans-=que.top();
17         que.pop();
18         tmp+=que.top();
19         ans-=que.top();
20         que.pop();
21         que.push(tmp);
22     }
23     cout<<ans<<endl;
24     return 0;
25 }

1245 最小的N个和

 时间限制: 1 s    空间限制: 128000 KB    题目等级 : 钻石 Diamond
 
题目描述 Description

有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。

输入描述 Input Description

第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi,
且Bi≤10^9

输出描述 Output Description

输出仅一行,包含 n 个整数,从小到大输出这 N个最小的和,相邻数字之间用
空格隔开。

样例输入 Sample Input

5

1 3 2 4 5 
6 3 4 1 7

样例输出 Sample Output

2 3 4 4 5

数据范围及提示 Data Size & Hint

【数据规模】 对于 100%的数据,满足 1≤N≤100000。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<queue>
 6 
 7 #define maxn 100010
 8 using namespace std;
 9 priority_queue<int,vector<int> > q;// 大头堆 专业建法 
10 int n,a[maxn],b[maxn],ans[maxn];
11 int main()
12 {
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
15     for(int i=1;i<=n;i++) scanf("%d",&b[i]);
16     sort(a+1,a+1+n);sort(b+1,b+1+n);
17     int p=2,cnt=0;
18     for(int i=1;i<=n;i++) q.push(b[1]+a[i]);
19     for(int i=1;i<=n;i++){
20         while(p<=n&&a[i]+b[p]<q.top()){
21             q.pop();
22             q.push(a[i]+b[p]);
23             p++;
24         }
25         p=2;
26     }
27     for(int i=n;i>=1;i--){
28         ans[i]=q.top();
29         q.pop();
30     }
31     for(int i=1;i<=n;i++) printf("%d ",ans[i]);
32     return 0;
33 }

1246 丑数  USACO

 时间限制: 1 s    空间限制: 128000 KB    题目等级 : 钻石 Diamond
题目描述 Description

对于一给定的素数集合 S = {p1, p2, ..., pK}, 
来考虑那些质因数全部属于S 的数的集合。这个集合包括,p1, p1p2, p1p1, 和 p1p2p3 (还有其它)。这是个对于一个输入的S的丑数集合。
注意:我们不认为1 是一个丑数。
你的工作是对于输入的集合S去寻找集合中的第N个丑数。longint(signed 32-bit)对于程序是足够的。

输入描述 Input Description

第 1 行: 二个被空间分开的整数:K 和 N , 1<= K<=100 , 1<= N<=100,000. 
第 2 行: K 个被空间分开的整数:集合S的元素

输出描述 Output Description

单独的一行,写上对于输入的S的第N个丑数。

样例输入 Sample Input

4 19
2 3 5 7

样例输出 Sample Output

27

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 long long p[105],s[100005];
 6 int k,n;
 7 int main()
 8 {
 9     memset(s,0x7f,sizeof(s)); 
10     scanf("%d%d",&k,&n);
11     for(int i=1;i<=k;i++)
12       scanf("%d",&p[i]);
13     s[0]=1;
14     for(int i=1;i<=n;i++){
15         for(int j=1;j<=k;j++){
16             int l=0,r=i-1,mid;
17             while(l<r){
18                 mid=(l+r)/2;
19                 if(s[mid]*p[j]>s[i-1]) r=mid;
20                 else l=mid+1;
21             }
22             s[i]=min(s[i],s[r]*p[j]);
23         }
24     }
25     printf("%d
",s[n]);
26     return 0;
27 }

3377 [Mz]接水问题2

 时间限制: 1 s    空间限制: 64000 KB    题目等级 : 钻石 Diamond
题目描述 Description

学校里有一个水房,水房里一共装有m个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1。

现在有n名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 1到n编号,i号同学的接水量为wi。接水开始时,1到m号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学j完成其接水量要求wj后,下一名排队等候接水的同学k马上接替j同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即j同学第x秒结束时完成接水,则k同学第x+1秒立刻开始接水。若当前接水人数n’不足m,则只有n’个龙头供水,其它m-n’个龙头关闭。  

现在给出n名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

特别地,同学们在打水前排好了队,接水所用时间更长的先接。

(ps:出题人本来想设计一个贪心的题目,然后发现用贪心做有反例,只能强改题目,在此声明道歉。不要在意样例解释。)

输入描述 Input Description

第 1 行2 个整数 n 和 m,用一个空格隔开,分别表示接水人数和龙头个数。  

第 2 行 n 个整数 w1、w2、„„、wn,每两个整数之间用一个空格隔开,wi表示 i 号同学的接水量。 

输出描述 Output Description

输出只有一行,1 个整数,表示接水所需的总时间。

样例输入 Sample Input

5 3

4 4 1 2 1

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

【输入输出解释】

第 1 秒,3 人接水。第 1秒结束时,1、2、3 号同学每人的已接水量为 1,3 号同学接完水,4 号同学接替 3 号同学开始接水。  

第 2 秒,3 人接水。第 2 秒结束时,1、2 号同学每人的已接水量为 2,4 号同学的已接水量为 1。  

第 3 秒,3 人接水。第 3 秒结束时,1、2 号同学每人的已接水量为 3,4 号同学的已接水量为 2。4号同学接完水,5 号同学接替 4 号同学开始接水。  

第 4 秒,3 人接水。第 4 秒结束时,1、2 号同学每人的已接水量为 4,5 号同学的已接水量为 1。1、2、5 号同学接完水,即所有人完成接水。 

【数据范围】
对于 30%的数据,n≤10,000,m≤1,000;
对于全部的数据,1≤m≤n≤1,000,000,1≤m≤100,000。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<queue>
 6 #define maxn 100010
 7 using namespace std;
 8 struct cmp{
 9     bool operator()(int &a,int &b){
10         return a>b;
11     }
12 };
13 priority_queue<int,vector<int>,cmp> q; 
14 int n,m,x,a[1000000+2];
15 int main()
16 {
17     scanf("%d%d",&n,&m);
18     for(int i=1;i<=n;i++)
19       scanf("%d",&a[i]);
20     sort(a+1,a+n+1); 
21     for(int i=1;i<=m;i++){
22         q.push(0);
23     }
24     for(int i=n;i>=1;i--){
25         int t=q.top();q.pop();
26         t+=a[i];
27         q.push(t);
28     }
29     int maxx=0;
30     while(!q.empty()){
31         maxx=max(maxx,q.top());
32         q.pop();
33     }
34     
35     printf("%d",maxx);
36     return 0;
37 }

很没意思的一道题~~

2830 蓬莱山辉夜

 时间限制: 1 s    空间限制: 32000 KB    题目等级 : 黄金 Gold
题目描述 Description

在幻想乡中,蓬莱山辉夜是月球公主,居住在永远亭上,二次设定说她成天宅在家里玩电脑,亦称NEET姬
一天,她要她帮忙升级月球的网络服务器,应为注册用户过多(月兔和地球上的巫女都注册了……),所以作为代理管理员(俗称网管)的她,非常蛋疼。
注册用户格式:
TouhouMaiden 2004 200
其中前面的Touhoumaiden是预设,不做更改,第一个数是标识,第二个数是每次接受信息访问的间隔用时。
你要做的事,就是给定一群用户及n,求出这n次信息访问中,访问到了谁?

presented by Izayoi sakuya

输入描述 Input Description

以题目预设格式输入,另起一行以‘#’结束,在其一行输入n

输出描述 Output Description

n行,每行输出第行次后,信息访问到了谁?若在一个时间有若干少女被访问到,输出字典序最小的那位少女的标识

样例输入 Sample Input
TouhouMaiden 2004 200
TouhouMaiden 2005 300
#
5
样例输出 Sample Output
2004
2005
2004
2004
2005
数据范围及提示 Data Size & Hint

标识和每次信息访问间隔均在integer内,n<=10000

原本是要用到堆,但深搜+时间即可搞定

数据有点少但也都够变态了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 using namespace std;
 5 struct kaguya{
 6     int time;
 7     int code;
 8     int now;
 9 } baka,mokou;
10 bool operator<(kaguya a,kaguya b)
11 {
12     if(a.now!=b.now)
13         return a.now>b.now;
14     else
15         return a.code>b.code;
16 }
17 int main()
18 {
19     priority_queue<kaguya> q;
20     int n;
21     string a;
22     while(cin>>a)
23     {
24         if(a=="#")break;
25         cin>>baka.code>>baka.time;
26         baka.now=baka.time;
27         q.push(baka);
28     }
29     cin>>n;
30     while(n--){
31         mokou=q.top();
32         q.pop();
33         cout<<mokou.code<<endl;
34         mokou.now+=mokou.time;
35         q.push(mokou);
36     }
37     return 0;
38 }

基本没读懂题目~~~

原文地址:https://www.cnblogs.com/suishiguang/p/6240727.html