[比賽][ICPC2020] 2020ICPC小米 網路選拔賽第一場
一、前言
聽說今年難得有場邀請賽,而且還是在北京線下,感覺是個大好的機會 —— 畢竟上次參加南昌場的邀請賽直接奪銀,感覺狀態再好點衝個金也沒問題。然而事實告訴我這並不是場一如既往的邀請賽,43 個名額實在少得可憐,而且學校似乎並沒有名額限制,以至於清北直接屠榜了,不知道是今年情況特殊還是這場比賽特殊。最後勉為其難寫了 5 道題,距離入圍依舊遙不可及。
二、比賽概況
1、比賽連結
https://ac.nowcoder.com/acm/contest/7501
2、題目情況
A題:數論 + 動態規劃
B 題:計算幾何 + 最短路
C 題(簽到題):模擬;
D 題:圖論
E 題:略
F 題:二分答案
G 題:略
H 題:略
I 題:搜尋(BFS)+ 圖論
J 題:二維字首和 + 二維差分
K 題:略
3、得分情況
AC 了 A, C, D, I, J 五道,終榜 rank300+。
三、題目分析
A. Intelligent Warehouse
1、題目連結
https://ac.nowcoder.com/acm/problem/211807
2、題面
In MI Intelligent Warehouse, there are nn products, where the i-th product is of size aiai. We always need to box producsts into all kinds of containers, and it will be safer and more cost efficient if for any two sizes of products, one is the other's multiple, since there won't be any residual room in one container. So for each boxing we need to choose some products that for any two chosen products, either ai
3、題目大意
給出數列 a,從中選出儘可能多的數,使任意兩個數之間存在倍數關係。
4、分析與思路
5、題解
6、程式碼
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define MAXV 10000010 5 #define MAXN 200010 6 7 const intmaxV = 1e7 + 1; 8 9 int n, a[MAXN], f[MAXV], p[MAXV], s[MAXV], cnt; 10 int pl[MAXN], ql[MAXN], ans, pc; 11 12 int solve(int d, int r) { 13 if (d < 0) return f[r]; 14 int res = 0; 15 for (int i = 0; i <= ql[d]; i++) { 16 res = max(solve(d - 1, r), res); 17 r /= pl[d]; 18 } 19 return res; 20 } 21 22 void work() { 23 p[1] = 1; 24 for (int i = 2; i < maxV; i++) { 25 if (!p[i]) 26 p[i] = i, s[cnt++] = i; 27 for (int j = 0; j < cnt && 1ll * i * s[j] < maxV; j++) { 28 p[i * s[j]] = s[j]; 29 if (i % s[j] == 0) break; 30 } 31 } 32 sort(a, a + n); 33 for (int i = 0; i < n; i++) { 34 int o = a[i]; 35 pc = 0; 36 while (o > 1) { 37 if (pc && pl[pc - 1] == p[o]) 38 ql[pc - 1]++; 39 else 40 pl[pc] = p[o], ql[pc] = 1, pc++; 41 o /= p[o]; 42 } 43 f[a[i]] = solve(pc - 1, a[i]) + 1; 44 ans = max(f[a[i]], ans); 45 } 46 cout << ans; 47 } 48 49 int main() { 50 cin >> n; 51 for (int i = 0; i < n; i++) 52 cin >> a[i]; 53 work(); 54 return 0; 55 }
C. Smart Browser
1、題目連結
https://ac.nowcoder.com/acm/problem/211809
2、題面
In some social platforms, there are some netizen who like to post "www". Since the string is like the grass, which contains plenty of "/\" shapes, so there are also some netizen who post "grass".
As a fast, smart, and convenient browser, MI Browser can recognize this kind of text and show some special effects. Specifically, given a string, MI Browser will determine the number of "/\" shapes made by character "w", where "w" itself and the gap between two adjacent "w"s both give one `/\` shape. If still not clear, please turn to sample input/output for more details.
As a MI fan, you want to detect the relationship between the special effects and the number of "/\" shapes, so the thing you should do first is to determine the number of "/\" shapes by yourself.
3、題目大意
給出一個字串,求出若干個由連續的 w 組成的子串。
4、分析與思路
5、題解
6、程式碼
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define MAXN 100005 5 6 int l, o = 1, tot, ans; 7 char a[MAXN]; 8 9 int main() { 10 cin >> a + 1; 11 l = strlen(a + 1); 12 while (o <= l) { 13 if (a[o] == 'w') { 14 tot = 0; 15 while (a[o] == 'w') o++, tot++; 16 ans += tot * 2 - 1; 17 } 18 o++; 19 } 20 cout << ans; 21 return 0; 22 }
D. Router Mesh
1、題目連結
https://ac.nowcoder.com/acm/problem/211810
2、題面
In a Mesh networking system, there are nn MI Routers, where mm pairs of MI Routers are bidirectionally connected. In order to check the stability of the system, for each MI Router, we should determine the number of connected components after removing itand relative connections from the system. And then assess that if we should add more MI Routers into the system. Print the numbers of connected components in residual system after removing each MI Router.
3、題目大意
給出由 n 個點,m 條邊組成的非連通無向圖,求出每次刪除其中一個點後的連通塊個數。
4、分析與思路
5、題解
6、程式碼
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 const int N = 3e5 + 50; 7 const int NN = 2e5 + 50; 8 const int M = 1e9 + 7; 9 int n,m; 10 struct Edge{ 11 int u,v,nxt,cut; 12 } e[N*2]; 13 int cnt = 1, head[N], dfn[N],low[N]; 14 int ans[N]; 15 int mx = 0; 16 int clk = 0; 17 #define multi_case 18 #undef multi_case 19 void add_edge(int u,int v) { 20 e[++cnt] = (Edge){u,v,head[u],0}; 21 head[u] = cnt; 22 e[++cnt] = (Edge){v,u,head[v],0}; 23 head[v] = cnt; 24 } 25 void pre() { 26 cin >> n >> m; 27 for(int i = 1; i <= m; i++) { 28 int v,u; 29 cin >> u >> v; 30 add_edge(u,v); 31 } 32 } 33 void Tarjan(int u,int fa) { 34 dfn[u]=low[u]=++clk; 35 ans[u] = 0; 36 int cnt = 0; 37 if(fa == 0) ans[u] = -1; 38 for(int i=head[u];i;i=e[i].nxt) { 39 int v = e[i].v; 40 if(!dfn[v]) 41 { 42 cnt++; 43 Tarjan(v,u); 44 low[u]=min(low[v],low[u]); 45 if(fa == 0) { 46 ans[u] = cnt-1; 47 } 48 else if(fa != 0 && low[v] >= dfn[u]) 49 ans[u]++; 50 } 51 else if(v != fa) 52 low[u]=min(low[u],dfn[v]); 53 } 54 } 55 void solve(int _case) { 56 int block_cnt = 0; 57 for(int i = 1; i <= n; i++) { 58 if(dfn[i] == 0) { 59 Tarjan(i,0); 60 block_cnt++; 61 } 62 } 63 for(int u = 1; u <= n; u++) { 64 65 printf("%d%c", block_cnt + ans[u], " \n"[u==n]); 66 } 67 } 68 int main() { 69 ios::sync_with_stdio(false); 70 cin.tie(0); 71 int t; 72 pre(); 73 #ifdef multi_case 74 cin >> t; 75 #else 76 t = 1; 77 #endif 78 for (int i = 1; i <= t; i++) { 79 solve(i); 80 } 81 return 0; 82 }
(樊總的程式碼)
I. Walking Machine
1、題目連結
https://ac.nowcoder.com/acm/problem/211810
2、題面
連結:https://ac.nowcoder.com/acm/problem/211820
來源:牛客網
Given a maze of size n×mn\times mn×m, where upper left corner is (1,1)(1,1) and lower right corner is (n,m)(n,m). For each cell (x,y)(x,y), there is exactly one character c(c∈{W,A,S,D})c(c∈{W,A,S,D}) on it, denoting the moving restriction:
* If c=Wc=W, you can only go up from this cell, specifically go from (x,y)(x,y) to (x−1,y)(x−1,y)
* If c=A, you can only go left from this cell, specifically go from(x,y) to (x,y−1)(x,y−1)
* If c=Sc=S, you can only go down from this cell, specifically go from (x,y)(x,y) to (x+1,y)(x+1,y)
* If c=Dc=D, you can only go right from this cell, specifically go from (x,y)(x,y) to (x,y+1)(x,y+1)
We say one is out if x<1x<1 orx>n or y<1y<1 or y>my>m holds, now you should determine the number of cells that one can be out if start walking on it.
3、題目大意
4、分析與思路
5、題解
6、程式碼
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 const int N = 1000 + 5; 7 const int M = 1e9 + 7; 8 int n,m; 9 char s[N][N]; 10 int ans[N][N]; 11 #define multi_case 12 #undef multi_case 13 bool out(int i,int j) { 14 return i <= 0 || i > n || j <= 0 || j > m; 15 } 16 bool dfs(int x,int y) { 17 if(out(x,y)) return true; 18 if(ans[x][y] == 1) return true; 19 if(ans[x][y] == 0) return false; 20 ans[x][y] = false; 21 22 int dx = x, dy = y; 23 if(s[x][y] == 'W') dx--; 24 else if(s[x][y] == 'S') dx++; 25 else if(s[x][y] == 'A') dy--; 26 else if(s[x][y] == 'D') dy++; 27 ans[x][y] = dfs(dx,dy); 28 return ans[x][y]; 29 } 30 void pre() { 31 cin >> n >> m; 32 for(int i = 1; i <= n; i++) { 33 cin >> (s[i]+1); 34 } 35 for(int i = 1; i <= n; i++) { 36 for(int j = 1; j <= m; j++) { 37 ans[i][j] = -1; 38 } 39 } 40 } 41 void solve(int _case) { 42 for(int i = 1; i <= n; i++) { 43 for(int j = 1; j <= m; j++) { 44 if(ans[i][j] == -1) dfs(i,j); 45 } 46 } 47 int cnt = 0; 48 for(int i = 1; i <= n; i++) { 49 for(int j = 1; j <= m; j++) { 50 if(ans[i][j]) cnt++; 51 } 52 } 53 printf("%d\n", cnt); 54 } 55 int main() { 56 // freopen("data.in","r",stdin); 57 // freopen("data.out","w",stdout); 58 ios::sync_with_stdio(false); 59 cin.tie(0); 60 int t; 61 pre(); 62 #ifdef multi_case 63 cin >> t; 64 #else 65 t = 1; 66 #endif 67 for (int i = 1; i <= t; i++) { 68 // printf("Case #%d: ",i); 69 solve(i); 70 } 71 return 0; 72 }
(樊總的程式碼)
J. Matrix Subtraction
1、題目連結
https://ac.nowcoder.com/acm/problem/211822
2、題面
Given a matrix M of size n×m and two integers a,b, determine weither it is possible to make all entrys of M zero by repeatedly choosing a×b submatrices and reduce the values in the chosen matrices by 1. If possible, print "^_^" in one line, or print "QAQ" in one line.
3、題目大意
給出一個 n * m 的矩陣,每次對一個 a * b 矩陣的每個元素減 1,求能夠將矩陣的元素全部變成 0。
4、分析與思路
5、題解
6、程式碼
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define fi first 4 #define se second 5 #define all(x) (x).begin(),(x).end() 6 #define mp make_pair 7 #define pb push_back 8 #define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0) 9 #define local freopen("in.text","r",stdin) 10 #define pi acos(-1) 11 const int mo=1e9+7; 12 typedef long long ll; 13 typedef pair<int,int> pii; 14 typedef vector<int> vi; 15 ll qp(ll a,ll b){if(a==0) return 0;ll res=1;a%=mo;for(;b;b>>=1){if(b&1)res=res*a%mo;a=a*a%mo;}return res;} 16 template<class T> bool read(T & ret)//ll,int,double,float,+/- 17 { 18 char c;int sgn;T bit=0.1;if(c=getchar(),c==EOF) return 0;while(c!='-' && c!='.' && (c<'0' || c>'9')) c=getchar();sgn=(c=='-')?-1:1;ret=(c=='-')?0:(c-'0');while(c=getchar(),c>='0' && c<='9') ret=ret*10+(c-'0');if(c==' '||c=='\n') {ret*=sgn;return 1;}while(c=getchar(),c>='0' && c<='9') ret+=(c-'0')*bit,bit/=10;ret*=sgn;return 1; 19 } 20 21 int a,b,n,m; 22 ll g[1010][1010]; 23 ll d[1010][1010]; 24 ll sum[1010][1010]; 25 26 void add(int x1,int y1,int x2,int y2,ll c) 27 { 28 d[x1][y1]+=c; 29 d[x2+1][y1]-=c; 30 d[x1][y2+1]-=c; 31 d[x2+1][y2+1]+=c; 32 } 33 34 ll get(int x,int y) 35 { 36 return sum[x-1][y]+sum[x][y-1]-sum[x-1][y-1]+d[x][y]; 37 } 38 void solve() 39 { 40 memset(sum,0,sizeof sum); 41 memset(d,0,sizeof d); 42 scanf("%d%d%d%d",&n,&m,&a,&b); 43 for(int i=1;i<=n;++i) 44 { 45 for(int j=1;j<=m;j++) 46 scanf("%lld",&g[i][j]); 47 } 48 int ok=1; 49 for(int i=1;i+a-1<=n;++i) 50 { 51 for(int j=1;j+b-1<=m;++j) 52 { 53 ll now=g[i][j]; 54 ll pre=get(i,j); 55 56 57 sum[i][j]=pre; 58 /* 59 for(int i=1;i<=n;++i) 60 { 61 for(int j=1;j<=m;++j) 62 { 63 printf("%d ",sum[i][j]); 64 } 65 puts(""); 66 } 67 */ 68 if(pre==now){ 69 sum[i][j]=pre; 70 continue; 71 } 72 else if(pre>now) { 73 ok=0;break; 74 } 75 else { 76 ll tt=now-pre; 77 add(i,j,i+a-1,j+b-1,tt); 78 sum[i][j] = get(i,j); 79 } 80 81 // cout<<"fuck:"<<endl; 82 83 84 } 85 86 for(int j=m-b+1;j<=m;++j){ 87 sum[i][j]=get(i,j); 88 if(sum[i][j]!=g[i][j]) { 89 ok=0;break; 90 } 91 } 92 if(!ok) break; 93 } 94 for(int i=n-a+1;i<=n;++i) 95 { 96 97 for(int j=1;j<=m;++j) 98 { 99 sum[i][j]=get(i,j); 100 if(sum[i][j]!=g[i][j]) { 101 ok=0; 102 break; 103 } 104 105 } 106 if(!ok) break; 107 } 108 /* for(int i=1;i<=n;++i) 109 { 110 for(int j=1;j<=m;++j) 111 { 112 printf("%d ",sum[i][j]); 113 } 114 puts(""); 115 } 116 */ 117 if(!ok) puts("QAQ"); 118 else puts("^_^"); 119 } 120 121 signed main(){ 122 123 int t; 124 cin>>t; 125 while(t--) 126 { 127 solve(); 128 } 129 130 return 0; 131 }
(lrj 的程式碼)