某模拟题题解
2016-08-29 17:29
162 查看
描述(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
描述(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
描述(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
一个城市的构成是一颗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
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cctype> #include<vector> using namespace std; typedef bool boolean; template<typename T> inline void readInteger(T& u){ char x; while(!isdigit((x = getchar()))); for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); ungetc(x, stdin); } typedef class Edge{ public: int end; int next; Edge(const int end = 0, const int next = 0):end(end),next(next){} }Edge; int ce; int *h; Edge* edge; inline void addEdge(int from, int end){ edge[++ce] = Edge(end, h[from]); h[from] = ce; } int n; int maxd; int noded; void dsearch(int node, int split, int depth, int last){ for(int i = h[node]; i != 0; i = edge[i].next){ if(i == split || i == split + 1 || edge[i].end == last) continue; dsearch(edge[i].end, split, depth + 1, node); } if(maxd <= depth){ maxd = depth; noded = node; } } int farSearch(int node, int split){ dsearch(node, split, 0, 0); int buf = noded; maxd = 0; dsearch(buf, split, 0, 0); return maxd; } inline void init(){ readInteger(n); edge = new Edge[(const int)(2 * n + 1)]; h = new int[(const int)(n + 1)]; memset(h, 0, sizeof(int) * (n + 1)); for(int i = 1, a, b; i < n; i++){ readInteger(a); readInteger(b); addEdge(a, b); addEdge(b, a); } } inline void solve(){ long long result = 0; long long a, b; for(int i = 1; i <= n; i++){ for(int j = h[i]; j != 0; j = edge[j].next){ if((j & 1) == 0) continue; a = farSearch(i, j); maxd = 0; b = farSearch(edge[j].end, j); maxd = 0; result = max(result, a * b); } } cout<<result; } int main(){ freopen("A.input", "r", stdin); freopen("A.output", "w", stdout); init(); solve(); return 0; }
描述(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
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cctype> #include<vector> using namespace std; typedef bool boolean; template<typename T> inline void readInteger(T& u){ char x; while(!isdigit((x = getchar()))); for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); ungetc(x, stdin); } typedef class sdata{ public: int _count; int times; sdata(int times = 0, int _count = 0):times(times), _count(_count){} }sdata; int n; long long k; int* a; int* b; vector<sdata> qs; inline void init(){ readInteger(n); readInteger(k); a = new int[(const int)(n + 1)]; b = new int[(const int)(n + 1)]; for(int i = 1; i <= n; i++) readInteger(a[i]); memcpy(b, a, sizeof(int) * (n + 1)); } inline void solve(){ sort(b + 1, b + n + 1); int _count = 0; for(int i = 1; i <= n; i++){ if(i != 1 && b[i] != b[i - 1]){ qs.push_back(sdata(b[i - 1], _count)); _count = 0; } _count++; } qs.push_back(sdata(b , _count)); int remain = n; //剩下的数量 int subed = 0; //已经减去的值,直接修改会浪费时间 for(int t = 0; (remain * 1LL * (qs[t].times - subed)) <= k && remain > 0; t++){ k -= remain * 1LL * (qs[t].times - subed); remain -= qs[t]._count; subed += qs[t].times - subed; } if(remain == 0) return; subed += k / remain; k %= remain; for(int i = 1; i <= n; i++) a[i] -= subed; int i; for(i = 1; i <= n && k; i++){ if(a[i] <= 0) continue; a[i]--; k--; } for(int j = i; j <= n; j++) if(a[j] > 0) printf("%d ", j); for(int j = 1; j < i; j++) if(a[j] > 0) printf("%d ", j); } int main(){ freopen("B.input", "r", stdin); freopen("B.output", "w", stdout); init(); solve(); return 0; }
描述(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
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cctype> #include<queue> #include<vector> using namespace std; typedef bool boolean; template<typename T> inline void readInteger(T& u){ char x; while(!isdigit((x = getchar()))); for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); ungetc(x, stdin); } typedef class Edge{ public: int end; int next; Edge(const int end = 0, const int next = 0):end(end),next(next){} }Edge; int ce; int *h; Edge* edge; int* in; inline void addEdge(int from, int end){ edge[++ce] = Edge(end, h[from]); h[from] = ce; in[end]++; } int n; int* room; inline void init(){ readInteger(n); room = new int[(const int)(n + 1)]; edge = new Edge[(const int)(n * n / 2 + 1)]; h = new int[(const int)(n + 1)]; in = new int[(const int)(n + 1)]; memset(h, 0, sizeof(int) * (n + 1)); memset(in, 0, sizeof(int) * (n + 1)); for(int i = 1; i <= n; i++) readInteger(room[i]); for(int i = 1, k, a; i <= n; i++){ readInteger(k); while(k--){ readInteger(a); addEdge(a, i); } } } int* deg; queue<int> que[3]; inline int tp_sort(int s){ deg = new int[(const int)(n + 1)]; memcpy(deg, in, sizeof(int) * (n + 1)); int _count = 0; for(int i = 1; i <= n; i++) if(deg[i] == 0){ _count++; que[room[i] - 1].push(i); } int status = s; int result = 0; while(_count){ while(!que[status].empty()){ //处理完所有可以做的任务 int u = que[status].front(); que[status].pop(); for(int i = h[u]; i != 0; i = edge[i].next){ deg[edge[i].end]--; if(deg[edge[i].end] == 0){ que[room[edge[i].end] - 1].push(edge[i].end); _count++; } } _count--; } if(_count == 0) break; result++; status++; if(status > 2) status = 0; } delete[] deg; return result + n; } int main(){ freopen("C.input", "r", stdin); freopen("C.output", "w", stdout); init(); int result = 0xfffffff; for(int i = 0; i < 3; i++) result = min(result, tp_sort(i)); printf("%d", result); return 0; }
相关文章推荐
- SCEA之路--第一次模拟题之后
- Zju 1710 The Snail又一道模拟题
- 希赛2009年网工模拟题6
- Sicily 1097 LED Modding(模拟题)
- POJ 1029 硬币称量类型二 与POJ 1013类比 模拟题
- HDU 2093-考试排名(模拟题)
- hdu 4039 字符串模拟题
- 模拟题3
- POJ 1029 硬币称量类型二 与POJ 1013类比 模拟题
- 【带权中位数】【120715测试】【朱全明NOIP模拟题】YL杯超级篮球赛
- poj1606-没想好就不要下手,否则浪费时间-模拟题的教训
- POJ 2632 Crashing Robots【模拟题】
- 新秀赛模拟题——①
- Ignatius and the Princess IV(hdu模拟题)
- LA 3708 - Graveyard 模拟题
- uva 12100 Printer Queue 优先级队列模拟题 数组模拟队列
- hdu4488 Faulhaber’s Triangle(模拟题)
- I am Nexus Master!(虽然只是个模拟题。。。但仍想了很久!)
- bnuoj 4207 台风(模拟题)
- ZOJ Problem Set - 3326 An Awful Problem(模拟题,待改正)