【2019湖北省大学程序设计竞赛】网赛
因为已经是大三老狗了,也是正在备考研究生中。。。所以只是申请了号自己打。(连群都不敢进)
感觉今年的题目还算简单的。QAQ。毕竟自己还能做。。(很久没碰真*算法了其实)
而且没有教练给的压力,打的格外开心。
下面就按照我自己做题的顺序来写题解啦。(并不是标程)
E
题意:给你一串数字,对应的是输入法中九键的键盘。n个测试样例的字符串,让你判断可不可能通过这串数字输出。
题解:还是比较简单的模拟。开了个map存对应的数字。然后每个测试字符串对应存一个对应的(数字)字符串,然后对比输入的数字。记得去除大小写和空格。。(我是钻了stl的空子我觉得)
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 map <char,char> mp; 5 6 void init(){ 7 mp['a']='2';mp['b']='2';mp['c']='2'; 8 mp['d']='3';mp['e']='3';mp['f']='3'; 9 mp['g']='4';mp['h']='4';mp['i']='4'; 10 mp['j']='5';mp['k']='5';mp['l']='5'; 11 mp['m']='6';mp['n']='6';mp['o']='6'; 12 mp['p']='7';mp['q']='7';mp['r']='7';mp['s']='7'; 13 mp['t']='8';mp['u']='8';mp['v']='8'; 14 mp['w']='9';mp['x']='9';mp['y']='9';mp['z']='9'; 15 } 16 17 void trim(string &s){ 18 int index = 0; 19 if( !s.empty()){ 20 while( (index = s.find(' ',index)) != string::npos){ 21 s.erase(index,1); 22 } 23 } 24 25 } 26 int main(){ 27 init(); 28 int T; 29 cin>>T; 30 for(int t = 1; t <= T; t++){ 31 string s; 32 cin>>s; 33 int n; 34 cin>>n; 35 printf("Case #%d:\n",t); 36 string ss; 37 getline(cin,ss); 38 while(n--){ 39 getline(cin,ss); 40 trim(ss); 41 transform(ss.begin(),ss.end(),ss.begin(),::tolower); 42 string res; 43 for(int i = 0; i < ss.size();i++){ 44 //cout<<mp[ss[i]]<<endl; 45 res += mp[ss[i]]; 46 } 47 if(res == s) cout<<"Maybe.."<<endl; 48 else cout<<"How could that be possible?"<<endl; 49 } 50 51 } 52 return 0; 53 }
B
题意:一个喝醉的小仓鼠,沿着上右下左的顺序走,问你n次后离原点的距离的平方是多少。
题解:也是个简单模拟。把原点当作(0,0),上下左右也就是对xy+-.(记得long long)。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 5 int main(){ 6 int T; 7 cin>>T; 8 for(int t = 1; t <= T; t++){ 9 int n; 10 cin>>n; 11 int x=0,y=0; 12 int xx; 13 14 for(int i = 0; i < n ;i++){ 15 cin>>xx; 16 if(i%4 == 0) y += xx; 17 else if(i%4 == 1) x += xx; 18 else if(i%4 == 2) y -= xx; 19 else if(i%4 == 3) x -= xx; 20 } 21 ll dis = x*x + y*y; 22 printf("Case #%d:%I64d\n",t,dis); 23 } 24 25 return 0; 26 }
F
题意:有n座山,给你n座山的高度,n-1条路。m次询问。u和v之间经过的山第k高是哪一座。
题解:一个主席树+LCA的静态区间查询第k小的模板题。。板子上是第k大,所以要改一下变成第k小。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxN = 1e5 + 7; 5 6 int N, M, a[maxN], b[maxN], diff, root[maxN][20], deep[maxN], cnt, head[maxN]; 7 int order, tree[maxN], lson[maxN*20], rson[maxN*20], siz[maxN*20]; 8 9 struct Eddge{ 10 int nex, to; 11 Eddge(int a=-1, int b=0):nex(a), to(b) {} 12 }edge[maxN<<1]; 13 14 void addEddge(int u, int v){ 15 edge[cnt] = Eddge(head[u], v); 16 head[u] = cnt++; 17 } 18 19 void dfs(int u, int pre, int depth){ 20 root[u][0] = pre; 21 deep[u] = depth; 22 for(int i=head[u]; i!=-1; i=edge[i].nex){ 23 int v = edge[i].to; 24 if(v == pre) continue; 25 dfs(v, u, depth + 1); 26 } 27 } 28 29 void pre_LCA(){ 30 dfs(1, 0, 0); 31 for(int j=0; (1<<(j+1))<N ; j++){ 32 for(int i=1; i<=N; i++){ 33 if(root[i][j] < 0) root[i][j+1] = -1; 34 else root[i][j+1] = root[root[i][j]][j]; 35 } 36 } 37 } 38 39 int get_LCA(int x, int y){ 40 if(deep[x] < deep[y]) swap(x, y); 41 int det = deep[x] - deep[y]; 42 for(int i=0; (1<<i)<=det; i++) if( (det>>i) & 1 ) x = root[x][i]; 43 if(x == y) return x; 44 for(int i = log2(1. * N); i>=0; i--){ 45 if(root[x][i] != root[y][i]){ 46 x = root[x][i]; 47 y = root[y][i]; 48 } 49 } 50 return root[x][0]; 51 } 52 53 void build(int &k, int l, int r){ 54 k = ++order; 55 siz[k] = 0; 56 if(l == r) return; 57 int mid = (l + r)>>1; 58 build(lson[k], l, mid); 59 build(rson[k], mid + 1, r); 60 } 61 62 void update(int old, int &now, int l, int r, int qx){ 63 now = ++order; 64 lson[now] = lson[old]; rson[now] = rson[old]; siz[now] = siz[old] + 1; 65 if(l == r) return; 66 int mid = (l + r)>>1; 67 if(qx <= mid) update(lson[old], lson[now], l, mid, qx); 68 else update(rson[old], rson[now], mid + 1, r, qx); 69 } 70 71 int query(int i, int j, int l, int r, int k, int lca, int fsa){ 72 if(l == r) return l; 73 int det = siz[lson[i]] + siz[lson[j]] - siz[lson[lca]] - siz[lson[fsa]]; 74 int mid = (l + r)>>1; 75 if(k <= det) return query(lson[i], lson[j], l, mid, k, lson[lca], lson[fsa]); 76 else return query(rson[i], rson[j], mid + 1, r, k - det, rson[lca], rson[fsa]); 77 } 78 79 void dfs_build(int u, int pre){ 80 int pos = (int)(lower_bound(b + 1, b + diff + 1, a[u]) - b); 81 update(tree[pre], tree[u], 1, diff, pos); 82 for(int i=head[u]; i!=-1; i=edge[i].nex){ 83 int v = edge[i].to; 84 if(v == pre) continue; 85 dfs_build(v, u); 86 } 87 } 88 89 void init(){ 90 memset(head, -1, sizeof(head)); 91 cnt = order = 0; 92 memset(root, -1, sizeof(root)); 93 } 94 95 int main(){ 96 int T; 97 cin>>T; 98 while(T--){ 99 scanf("%d%d", &N, &M); 100 init(); 101 for(int i=1; i<=N; i++){ 102 scanf("%d", &a[i]); 103 b[i] = a[i]; 104 } 105 106 sort(b + 1, b + N + 1); 107 diff = (int)(unique(b + 1, b + N + 1) - b - 1); 108 for(int i=1; i<N; i++){ 109 int e1, e2; scanf("%d%d", &e1, &e2); 110 addEddge(e1, e2); 111 addEddge(e2, e1); 112 } 113 pre_LCA(); 114 build(tree[0], 1, diff); 115 dfs_build(1, 0); 116 for(int i=1; i<=M; i++){ 117 int l, r, op; scanf("%d%d%d", &l, &r, &op); 118 int lca = get_LCA(l, r); 119 //第k大变成第k小 120 op = deep[l] + deep[r] - 2 * deep[lca] - op + 2; 121 if(op<=0) printf("-1\n"); 122 else 123 printf("%d\n", b[query(tree[l], tree[r], 1, diff, op, tree[lca], tree[root[lca][0]])]); 124 } 125 } 126 return 0; 127 }
D
题意:蒲公英的种子最开始在点(0,0),没风的时候上走,有风的时候向右走。它要到(m,n)请问有多少种走法。
题解:经典。组合数问题啊。QAQ我记得我区预赛卡死在组合数上了。公式:C(n+m-1,m) - C(n+m-1,m-1)。记得取模。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn = 500005, MOD = 1e9 + 7; 5 int F[maxn], Finv[maxn], inv[maxn];//F是阶乘,Finv是逆元的阶乘 6 void init(){ 7 inv[1] = 1; 8 for(int i = 2; i < maxn; i ++){ 9 inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD; 10 } 11 F[0] = Finv[0] = 1; 12 for(int i = 1; i < maxn; i ++){ 13 F[i] = F[i-1] * 1ll * i % MOD; 14 Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD; 15 } 16 } 17 int comb(int n, int m){ 18 if(m < 0 || m > n) return 0; 19 return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD; 20 } 21 22 int main() { 23 init(); 24 int n, m; 25 int t; 26 scanf("%d",&t); 27 while (t--) { 28 scanf("%d%d", &m, &n); 29 printf("%d\n", (comb(n + m - 1, m) - comb(n + m - 1, m - 1) + MOD) % MOD); 30 } 31 return 0; 32 }
A(计算几何)和C(线段树)我一时没有想到什么好的办法。打算看了标程再补一下题。。QAQ。