某模拟题题解

描述(A 输入文件 : A.input 输出文件 : A.output)
一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路
径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大。
输入描述
第一行一个数n 表示这个城市一共有 n 个节点。
接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边
的长度为1。
输出描述
输出一行一个数表示两条路径长度最大的乘积。
样例数据
样例输入1:
7
1 2
1 3
1 4
1 5
1 6
1 7
样例输出1:
0
样例输入2:
6
1 2
2 3
2 4
5 4
6 4
样例输出2:
4


  第一题没多大技术含量,枚举每一条边,把这棵树分成两棵子树,再在这两棵子树上求最大的路径,这里用两种

方法,第一种是树规,第二种是两次dfs,第一种这里就不讲了,就说第二种,首先从一个点开始深搜,找到一个离当

前点最远的一个点,再从这个点开始,找到一个离这个点最远的点,这两个点的距离是最远的。

  然后两部分都执行以下这个,找出这个距离,相乘,不断更新结果就行了

Code

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cctype>
 6 #include<vector>
 7 using namespace std;
 8 typedef bool boolean;
 9 template<typename T>
10 inline void readInteger(T& u){
11     char x;
12     while(!isdigit((x = getchar())));
13     for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
14     ungetc(x, stdin);
15 }
16 typedef class Edge{
17     public:
18         int end;
19         int next;
20         Edge(const int end = 0, const int next = 0):end(end),next(next){}
21 }Edge;
22 int ce;
23 int *h;
24 Edge* edge;
25 inline void addEdge(int from, int end){
26     edge[++ce] = Edge(end, h[from]);
27     h[from] = ce;
28 }
29 int n;
30 int maxd;
31 int noded;
32 void dsearch(int node, int split, int depth, int last){
33     for(int i = h[node]; i != 0; i = edge[i].next){
34         if(i == split || i == split + 1 || edge[i].end == last)    continue;
35         dsearch(edge[i].end, split, depth + 1, node);
36     }
37     if(maxd <= depth){
38         maxd = depth;
39         noded = node;
40     }
41 }
42 int farSearch(int node, int split){
43     dsearch(node, split, 0, 0);
44     int buf = noded;
45     maxd = 0;
46     dsearch(buf, split, 0, 0);
47     return maxd;
48 }
49 inline void init(){
50     readInteger(n);
51     edge = new Edge[(const int)(2 * n + 1)];
52     h = new int[(const int)(n + 1)];
53     memset(h, 0, sizeof(int) * (n + 1));
54     for(int i = 1, a, b; i < n; i++){
55         readInteger(a);
56         readInteger(b);
57         addEdge(a, b);
58         addEdge(b, a);
59     }
60 }
61 inline void solve(){
62     long long result = 0;
63     long long a, b;
64     for(int i = 1; i <= n; i++){
65         for(int j = h[i]; j != 0; j = edge[j].next){
66             if((j & 1) == 0)    continue;
67             a = farSearch(i, j);
68             maxd = 0;
69             b = farSearch(edge[j].end, j);
70             maxd = 0;
71             result = max(result, a * b);
72         }
73     }
74     cout<<result;
75 }
76 int main(){
77     freopen("A.input", "r", stdin);
78     freopen("A.output", "w", stdout);
79     init();
80     solve();
81     return 0;
82 }

描述(B 输入文件 : B.input 输出文件 : B.output)
有n 个人需要看医生, 其中第i 个人需要看医生的次数是ai, 一开始从1 到n 依次排列组成
一个等待队伍, 每个人依次看医生, 那么每个人看完医生有两种情况, 第一种情况:他
已经看够他需要看医生的次数,那么他会离开。第二种情况:他还需要看医生,那么他就
会选择重新站在队伍的最后。选择医生想知道,当他看过k 次病人之后,这个等待队伍是
什么样。
输入描述
第一行两个正整数 n 和 k (1 ≤ n ≤ 105, 0 ≤ k ≤ 1014)
第二行一共个n 正整数 a1, a2, ..., an (1 ≤ ai ≤ 109),用空格隔开。
输出描述
一行,按队列的顺序输出需要的结果,每两个数之间用空格隔开,注意不要输出多余的空
格。数据保证此时队列里至少有一个人。
样例数据
样例输入1:
3 3
1 2 1
样例输出1:
2
样例输入2:
7 10
1 3 3 1 2 3 1
样例输出2:
6 2 3


  这道含金量不大,主要是这坑人的数据范围。。。O(k)的算法都会TLE,怎么办?不断把k减小,

首先从小到大排个序,然后看k次后排序后的第i个人有没有看完,看完了就把所有人已经看了的次数加上

这个数(不直接去更新,否则速度会变慢很多),一直到最后剩下次数不能使一个人离开队列

  接着剩下的人每个人至少还可以看k / remain次,所以每个人至少看的次数还要加上这么多

最后就直接模拟,输出。

Code

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cctype>
 6 #include<vector>
 7 using namespace std;
 8 typedef bool boolean;
 9 template<typename T>
10 inline void readInteger(T& u){
11     char x;
12     while(!isdigit((x = getchar())));
13     for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
14     ungetc(x, stdin);
15 }
16 typedef class sdata{
17     public:
18         int _count;
19         int times;
20         sdata(int times = 0, int _count = 0):times(times), _count(_count){}
21 }sdata;
22 int n;
23 long long k;
24 int* a;
25 int* b;
26 vector<sdata> qs;
27 inline void init(){
28     readInteger(n);
29     readInteger(k);
30     a = new int[(const int)(n + 1)];
31     b = new int[(const int)(n + 1)];
32     for(int i = 1; i <= n; i++)
33         readInteger(a[i]);
34     memcpy(b, a, sizeof(int) * (n + 1));
35 }
36 inline void solve(){
37     sort(b + 1, b + n + 1);
38     int _count = 0;
39     for(int i = 1; i <= n; i++){
40         if(i != 1 && b[i] != b[i - 1]){
41             qs.push_back(sdata(b[i - 1], _count));
42             _count = 0;
43         }
44         _count++;
45     }
46     qs.push_back(sdata(b[n], _count));
47     
48     int remain = n;        //剩下的数量 
49     int subed = 0;        //已经减去的值,直接修改会浪费时间 
50     for(int t = 0; (remain * 1LL * (qs[t].times - subed)) <= k && remain > 0; t++){
51         k -= remain * 1LL * (qs[t].times - subed);
52         remain -= qs[t]._count;
53         subed += qs[t].times - subed;
54     }
55     
56     if(remain == 0)    return;
57     subed += k / remain;
58     k %= remain;
59     
60     for(int i = 1; i <= n; i++)    a[i] -= subed;
61     int i;
62     for(i = 1; i <= n && k; i++){
63         if(a[i] <= 0)    continue;
64         a[i]--;
65         k--;
66     }
67     
68     for(int j = i; j <= n; j++)
69         if(a[j] > 0)    printf("%d ", j);
70     for(int j = 1; j < i; j++)
71         if(a[j] > 0)    printf("%d ", j);
72 }
73 int main(){
74     freopen("B.input", "r", stdin);
75     freopen("B.output", "w", stdout);
76     init();
77     solve();
78     return 0;
79 }

描述(C 输入文件 : C.input 输出文件 : C.output)
有n 个任务需要你去完成,这些任务分布在3 个不同的房间,编号为1,2,3, 其中有些任务
必须在一些其他的任务完成之后才能完成。现在知道完成一个任务需要1 的时间,现在知
从房间1 到2,2 到3,3 到1 需要1 的时间,从1 到3,2 到1,3 到2 需要2 的时间。现
在你可以选择你一开始的房间,问完全所有任务的最短时间是多少,保证可以完成。
输入描述
第一行一个数 n (1 ≤ n ≤ 200) 。
第二行 n 个数, 第i 个数 ci (1 ≤ ci ≤ 3) 表示该任务所在的房间。.
接下来一共 n 行. 第 i 行的第一个数是 ki (0 ≤ ki ≤ n - 1),表示完成第i 个任务之前需要完
成的任务个数,之后 ki 个正整数表示需要提前完成的任务的编号。
输出描述
输出一个正整数表示完成任务需要是时间。
样例数据
样例输入1:
5
2 2 1 1 3
1 5
2 5 1
2 5 4
1 5
0
样例输出1:
7


  首先可以发现从1走到3,还不如从1走到2再走到3,虽然在路上花费的时间是一样的,但是可能可以处理

更多的任务。像样思考,从某个房间开始到最后一个任务处理完毕的方案是唯一的,唯一影响结果的就是开始

的房间,所以枚举开始的房间然后拓扑排序就行了。

Code

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cctype>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 typedef bool boolean;
10 template<typename T>
11 inline void readInteger(T& u){
12     char x;
13     while(!isdigit((x = getchar())));
14     for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
15     ungetc(x, stdin);
16 }
17 typedef class Edge{
18     public:
19         int end;
20         int next;
21         Edge(const int end = 0, const int next = 0):end(end),next(next){}
22 }Edge;
23 int ce;
24 int *h;
25 Edge* edge;
26 int* in;
27 inline void addEdge(int from, int end){
28     edge[++ce] = Edge(end, h[from]);
29     h[from] = ce;
30     in[end]++;
31 }
32 int n;
33 int* room;
34 inline void init(){
35     readInteger(n);
36     room = new int[(const int)(n + 1)];
37     edge = new Edge[(const int)(n * n / 2 + 1)];
38     h = new int[(const int)(n + 1)];
39     in = new int[(const int)(n + 1)];
40     memset(h, 0, sizeof(int) * (n + 1));
41     memset(in, 0, sizeof(int) * (n + 1));
42     for(int i = 1; i <= n; i++)
43         readInteger(room[i]);
44     for(int i = 1, k, a; i <= n; i++){
45         readInteger(k);
46         while(k--){
47             readInteger(a);
48             addEdge(a, i);
49         }
50     }
51 }
52 int* deg;
53 queue<int> que[3];
54 inline int tp_sort(int s){
55     deg = new int[(const int)(n + 1)];
56     memcpy(deg, in, sizeof(int) * (n + 1));
57     int _count = 0;
58     for(int i = 1; i <= n; i++)
59         if(deg[i] == 0){
60             _count++;
61             que[room[i] - 1].push(i);
62         }
63     int status = s;
64     int result = 0;
65     while(_count){
66         while(!que[status].empty()){                //处理完所有可以做的任务 
67             int u = que[status].front();
68             que[status].pop();
69             for(int i = h[u]; i != 0; i = edge[i].next){
70                 deg[edge[i].end]--;
71                 if(deg[edge[i].end] == 0){
72                     que[room[edge[i].end] - 1].push(edge[i].end);
73                     _count++;
74                 }
75             }
76             _count--;
77         }
78         if(_count == 0)    break;
79         result++;
80         status++;
81         if(status > 2)    status = 0;
82     }
83     delete[] deg;
84     return result + n;
85 }
86 int main(){
87     freopen("C.input", "r", stdin);
88     freopen("C.output", "w", stdout);
89     init();
90     int result = 0xfffffff;
91     for(int i = 0; i < 3; i++)    result = min(result, tp_sort(i));
92     printf("%d", result);
93     return 0;
94 }

 

posted @ 2016-08-29 17:29  阿波罗2003  阅读(171)  评论(0编辑  收藏  举报