2017_SDNU_ACM-ICPC_Provincial_Team_Selection_Round_2【--完结--】
来源:互联网 发布:windows 程序返回值 编辑:程序博客网 时间:2024/05/17 09:29
山东省第八届acm大学程序设计竞赛山师选拔赛第二场
(声明:标题是自己取的,如果有语法错误的话与他人无关)
Problem_A(最近公共祖先)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <queue>using namespace std;const int MAXN = 10010;const int DEG = 20;struct Edge{ int to,next;} edge[MAXN*2];int head[MAXN],tot;void addedge(int u,int v){ edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++;}void init(){ tot = 0; memset(head,-1,sizeof(head));}int fa[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先int deg[MAXN];//深度数组void BFS(int root){ queue<int>que; deg[root] = 0; fa[root][0] = root; que.push(root); while(!que.empty()) { int tmp = que.front(); que.pop(); for(int i = 1; i < DEG; i++) fa[tmp][i] = fa[fa[tmp][i-1]][i-1]; for(int i = head[tmp]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa[tmp][0])continue; deg[v] = deg[tmp] + 1; fa[v][0] = tmp; que.push(v); } }}int LCA(int u,int v){ if(deg[u] > deg[v])swap(u,v); int hu = deg[u], hv = deg[v]; int tu = u, tv = v; for(int det = hv-hu, i = 0; det ; det>>=1, i++) if(det&1) tv = fa[tv][i]; if(tu == tv)return tu; for(int i = DEG-1; i >= 0; i--) { if(fa[tu][i] == fa[tv][i]) continue; tu = fa[tu][i]; tv = fa[tv][i]; } return fa[tu][0];}bool flag[MAXN];int main(){ int T; int n; int u,v; while(~scanf("%d",&n)) { init(); memset(fa,0,sizeof(fa)); memset(deg,0,sizeof(deg)); memset(flag,false,sizeof(flag)); for(int i = 1; i < n; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); flag[v] = true; } int root; for(int i = 1; i <= n; i++) if(!flag[i]) { root = i; break; } BFS(root); scanf("%d%d",&u,&v); if(LCA(u,v)) printf("%d\n",LCA(u,v)); else puts("I am so bad."); } return 0;}
Problem_B(矩阵快速幂)
题意:对任意的(1+sqrt(2)) ^n我们是否能找到对应的m使得上式化简为sqrt(m) +sqrt(m-1),如果有,请输出m%(1e9+7)的值,没有输出"I want to talk a joke."
思路:先写几个数字看看什么情况。化简后会看出(整数部分)系数为1、3、7、17……带有sqrt(2)的部分的系数为1、2、5、12……后者数值等于它上一个数的这两部分的系数之和(2=1+1,5=3+2,12=7+5……),前者的数值等于和他一个数的sqrt(2)的部分的系数+它上一个数的sqrt(2)的部分的系数(3=2+1,7=5+2,17=12+5……)。根据这个规律构造一个四阶矩阵,然后套上模板就可以了。注意每次乘完都要%MOD一下,防止溢出。
关于输出:如果n是奇数的话,就输出(整数部分)系数的^2,否则输出它的^2+1(自己推一推便知道了。
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int MAX = 10010;const int MOD = 1e9 + 7;const int ch = 4;struct matrix{ long long mat[ch][ch];};matrix multiply(matrix a, matrix b) //构造矩阵乘法{ int i, j, k; matrix t; memset(t.mat, 0, sizeof(t. mat)); for(i = 0; i < ch; ++i) for(j = 0; j < ch; ++j) for(k = 0; k < ch; ++k) t.mat[i][j] = (t.mat[i][j] + a.mat[i][k]*b.mat[k][j]%MOD) % MOD; return t;}long long fibonacci(long long n){ long long tem = n; n--; matrix base, ans; memset(base.mat, 0, sizeof(base.mat)); memset(ans.mat, 0, sizeof(ans.mat)); base.mat[2][0] = base.mat[2][2] = base.mat[3][1] = base.mat[3][2] = base.mat[3][3] = 1; base.mat[2][3] = 2; ans.mat[0][1] = ans.mat[0][0] = 1; ans.mat[0][2] = 2; ans.mat[0][3] = 3; while(n) { if(n & 1) ans = multiply(ans, base); base = multiply(base, base); n >>= 1; } //cout << tem << endl; if(!(tem&1)) return ans.mat[0][1]*ans.mat[0][1]%MOD; return (ans.mat[0][1]*ans.mat[0][1]+1)%MOD;}int main(){ long long n; while(cin >> n) cout << fibonacci(n) << endl; return 0;}
Problem_C(签到题)
题意:给定1-n个城市,你处在x位置,求出满足|x-i|<=r的正整数i的可能取到的数。
思路:因为给定了n的范围,所以一共会有4种情况,即左越界,左不越界,右越界,右不越界。4个if,轻松搞定。(我这个人比较懒,用一个for遍历了一遍,符合条件就让ans++,否则不作操作。比较而言当然是前者时间复杂度更低了,比赛时当然是要选择最优解法。
AC代码:
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;int main(){ int t; double n, r, x; //用int就行 scanf("%d",&t); while(t--) { int ans = 0; scanf("%lf%lf%lf",&n,&r,&x); for(int i = 1; i <= n; ++i) { if(fabs(x-i) <= r) ans++; } cout << ans << endl; } return 0;}
Problem_D(线段树单点更新求和+期望公式)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int MAX = 1<<16;struct node{ int l, r; long long sum, sum2;} tree[MAX<<2];long long a[MAX];long long sum, sum2;void pushup(int rt){ tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; tree[rt].sum2 = tree[rt<<1].sum2 + tree[rt<<1|1].sum2;}void build(int l, int r, int rt){ tree[rt].l = l; tree[rt].r = r; tree[rt].sum = 0; if(l == r) { tree[rt].sum = a[l]; tree[rt].sum2 = a[l]*a[l]; return ; } int mid = (tree[rt].l + tree[rt].r) >> 1; //递归建树 build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt);}void update(int x, int y, int rt){ //更新这个区间的值 if(tree[rt].l == tree[rt].r) { tree[rt].sum = y; tree[rt].sum2 = y*y; return ; } int mid = (tree[rt].l + tree[rt].r) >> 1; if(x <= mid) update(x, y, rt<<1); else update(x, y, rt<<1|1); pushup(rt);}void query(int x, int y, int rt){ if(tree[rt].l == x && tree[rt].r == y) { sum += tree[rt].sum; sum2 += tree[rt].sum2; return ; } int mid = (tree[rt].l + tree[rt].r) >> 1; if(y <= mid) query(x, y, rt<<1); else if(x > mid) query(x, y, rt<<1|1); else { query(x, mid, rt<<1); query(mid+1, y, rt<<1|1); }}int main(){ int n, m; while(~scanf("%d%d",&n,&m)) { for(int i = 1; i <= n; ++i) scanf("%lld",&a[i]); build(1, n, 1); while(m--) { int q; scanf("%d",&q); if(q == 1) { int pos, num; scanf("%d%d",&pos,&num); update(pos, num, 1); } else { int l, r; sum = sum2 = 0; scanf("%d%d",&l,&r); query(l, r, 1); long long ans = (r-l+1)*sum2 - sum*sum; cout << ans << endl; } } } return 0;}
Problem_E(最短路)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <sstream>using namespace std;const int INF = 0x3f3f3f3f;const int MAX = 510;int n;int adj[MAX][MAX];int a[MAX], dis[MAX];bool vis[MAX];void init(){ for(int i = 1; i <= 500; ++i) { for(int j = 1; j <= 500; ++j) { if(i == j) adj[i][j] = 0; else adj[i][j] = INF; } }}void Dij(){ int tem, minx; memset(vis, false, sizeof(vis)); for(int i = 0; i <= n; ++i) dis[i] = adj[1][i]; dis[1] = 0; vis[1] = true; for(int i = 1; i < n; ++i) { minx = INF; for(int j = 1; j <= n; ++j) { if(!vis[j] && dis[j] < minx) { minx = dis[j]; tem = j; } } if(minx == INF) break; vis[tem] = 1; for(int j = 1; j <= n; ++j) { if(!vis[j] && adj[tem][j] != INF && dis[tem] + adj[tem][j] <dis[j]) { dis[j] = adj[tem][j] + dis[tem]; } } }}int main(){ int t; int item; string stem, s; while(~scanf("%d",&t)) { init(); scanf("%d",&n); getchar(); while(t--) { int cou = 0; getline(cin, stem); stringstream ss (stem); while(ss >> item) { a[cou++] = item; } for(int i = 0; i < cou-1; ++i) for(int j = i+1; j < cou; ++j) { adj[a[i]][a[j]] = 1; } } Dij(); if(dis[n] == INF) cout << "-1" << endl; else cout << dis[n]-1 << endl; } return 0;}
Problem_F(思维)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int N = 5e6 + 5;int a[N];int main(){ int n; bool flag; int ans1, ans2, tem1, tem2; while(~scanf("%d",&n)) { flag = true; ans1 = ans2 = -1; tem1 = 0; tem2 = -1; for(int i = 0; i < n; ++i) scanf("%d",&a[i]); for(int i = 1; i < n; ++i) { if(a[i-1] == a[i]) { if(tem2 - tem1 > ans2 - ans1)//更新答案 { ans2 = tem2; ans1 = tem1; } tem1 = tem2 = -1; continue; } if(a[i-1] < a[i]) //上升 { if(!flag) { if(tem2 - tem1 > ans2 - ans1)//更新答案 { ans2 = tem2; ans1 = tem1; } flag = 1; tem1 = tem2 = -1; } if(tem1 == -1) tem1 = i-1; //cout << i << "--" << tem1 << endl; } else { flag = 0; if(tem1 != -1) tem2 = i; } if(tem2 - tem1 > ans2 - ans1)//更新答案 { ans2 = tem2; ans1 = tem1; } } if(ans1 != -1 && ans2 != -1) cout << ans1 << " " << ans2 << endl; else cout << "-1 -1" << endl; } return 0;}
Problem_G(并查集)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <queue>using namespace std;const int MAX = 1000;int tot, area, peri, cou;int f[MAX*MAX+5]; //记录是否联通char mapa[MAX+5][MAX+5]; //存图int dir[][2] = {0,1,0,-1,1,0,-1,0};void init(){ for(int i = 0; i <= MAX*MAX; ++i) { f[i] = i; }}int getf(int v){ if(f[v] != v) f[v] = getf(f[v]); return f[v];}int merg(int u, int v){ int t1 = getf(u); int t2 = getf(v); /*cout << u << "--" << v << endl; cout << t1 << "----" << t2 << endl << endl;*/ if(t1 != t2) { f[t2] = t1; return 1; //与周围的岛屿之前不连通 } return 0;}void solve(int x, int y){ int xx, yy; for(int i = 0; i < 4; ++i) { xx = x + dir[i][0]; yy = y + dir[i][1]; if(xx < 0 || xx >= MAX || yy < 0 || yy > MAX) continue; if(mapa[xx][yy] != '#') continue; //cout << xx << "---" << yy << endl; if(merg(x*MAX+y, xx*MAX+yy)) //联通成功,总岛屿数-1 { tot--; } peri -= 2; //周围有一个岛屿的话,周长-2 }}int main(){ int t; int x, y; while(~scanf("%d",&t)) { init(); tot = area = peri = 0; memset(mapa, 0, sizeof(mapa)); while(t--) { scanf("%d%d",&x,&y); if(mapa[x][y] == '#') { cout << tot << " " << area << " " << peri << endl; continue; } //先假设新加入的岛屿与其他都不连通 tot++; area++; peri += 4; mapa[x][y] = '#'; //开始做减法 solve(x, y); cout << tot << " " << area << " " << peri << endl; } } return 0;}
Problem_H(博弈+大数)
import java.math.BigInteger;import java.math.BigDecimal;import java.util.*;public class Main {public static void main(String[] args){Scanner scanner = new Scanner(System.in);int T;BigInteger n;BigInteger MOD = new BigInteger("5");T = scanner.nextInt();while((T--) > 0){n = scanner.nextBigInteger();if(n.mod(MOD).compareTo(BigInteger.ZERO) == 0)System.out.println("chaochao");else System.out.println("huahua");}}}
Problem_I(素数打表)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int MAX = 1500005;int a[MAX], tot;bool vis[MAX];void init()//筛法求a数组{ memset(vis, false, sizeof(vis)); //vis[0] = vis[1] = true; tot = 0; int M = sqrt(MAX+0.5); for(int i = 2; i <= M; ++i) { if(!vis[i]) { a[tot++] = i; for(int j = i*i; j <= MAX; j += i) { vis[j] = true; } } }}int main(){ init(); int t, n; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i = 0; i < tot; ++i) { if(!vis[n+a[i]]) { cout << n+a[i] << " " << a[i] << endl; break; } } } return 0;}
Problem_J(贪心)
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int MAX = 20005;long long a[MAX];int main(){ int n; long long ans; while(~scanf("%d",&n)) { ans = 0; for(int i = 0; i < n; ++i) { scanf("%lld",&a[i]); } sort(a, a+n); int tot = 1; while(tot < n) { a[tot] = a[tot] + a[tot-1]; ans += a[tot]; for(int i = tot; i < n-1; ++i) { if(a[i] <= a[i+1]) break; swap(a[i], a[i+1]); } tot++; /*cout << " tot=" << tot << endl; for(int i = 0; i < n; ++i) cout << a[i] << " "; cout << endl;*/ } //cout << endl; cout << ans << endl; } return 0;}
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <queue>#include <vector>using namespace std;struct cmp //自定义优先级{ bool operator () (long long &a, long long &b) const { //最小值优先 return a > b; }};int main(){ int n; long long ans, tem; priority_queue<long long, vector<long long>, cmp >pq; //因为priority_queue中有已经定义好的越小的整数优先级越大,所以可以直接调用 //priority_queue<long long, vector<long long>, greater<long long> >pq; while(~scanf("%d",&n)) { ans = 0; while(!pq.empty()) pq.pop(); while(n--) { scanf("%lld",&tem); pq.push(tem); } while(!pq.empty()) { tem = pq.top(); pq.pop(); if(pq.empty()) break; //cout << "tem=" << tem << endl; tem += pq.top(); pq.pop(); //cout << "tem2=" << tem << endl; ans += tem; pq.push(tem); } cout << ans << endl; } return 0;}
选拔赛结束了,虽然以排名比较靠前的成绩进了正式队,但是心里很是不甘,特别是这一次,很多能做的题都没做出来,还有一开始I的数据范围看错+打表打错,浪费了太多时间也影响了整体士气(我的锅。
还剩25天了,多学知识的同时也要修炼自己沉稳的性格,不管结果如何,不留遗憾就好。
- 2017_SDNU_ACM-ICPC_Provincial_Team_Selection_Round_2【--完结--】
- 2017_SDNU_ACM-ICPC_Provincial_Team_Selection_Round_1【--完结--】
- 2017_SDNU_ACM/ICPC_Freshman's Easy Game
- SDNU ACM-ICPC 2016-2017 Training Weekly Contest 1 【--完结--】
- SDNU ACM-ICPC 2016-2017 Training Weekly Contest 2 【--完结--】
- 毕业设计---完结
- DRP完结
- DRP完结
- 63、完结
- 日常(完结了,都完结了)
- 2017年第0届浙江工业大学之江学院程序设计竞赛决赛(完结)
- 香鸡排三部曲:完结篇
- C++学习心得--完结
- Oracle 学习12(完结)
- 今天的完结
- MP3播放器完结
- wireshark研究,阶段性完结
- 2010已经完结
- HM Deblocking代码阅读
- break,continue,return
- Android WebView的使用(一)
- 免密登录的shell脚本
- 模板的特化和偏特化
- 2017_SDNU_ACM-ICPC_Provincial_Team_Selection_Round_2【--完结--】
- Unity5.×烘焙常规处理步骤
- 常用页面置换算法总结
- 几种常用的排序方法
- Ant入门基础教程
- 阿里云ubuntu 16.04 Server配置方案 4 VPS面板 ajenti
- 二叉树的层次遍历
- 初识设备驱动程序之Hello world
- SQL Server 2008 自动备份数据库