直接比较字典序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <bits/stdc++.h> using namespace std;int main () { string a, b; cin >> a >> b; if (a > b) { cout << a << ">" << b << "\n" ; } else if (a < b) { cout << a << "<" << b << "\n" ; } else { cout << a << "=" << b << "\n" ; } return 0 ; }
细节比较多的签到,主要是0的问题。若R = 0,那么一枪都开不出,否则能开出 ⌊RxS/60⌋ + 1枪。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <bits/stdc++.h> using namespace std;int main () { int t; scanf ("%d" , &t); while (t--) { int b, r, d, s; scanf ("%d%d%d%d" , &b, &r, &d, &s); if (r == 0 ) { if (d > 0 ) { printf ("gua!\n" ); } else { printf ("ok\n" ); } } else if (s == 0 ) { if (d > b) { printf ("gua!\n" ); } else { printf ("ok\n" ); } } else { int ans = s * r; int cnt; cnt = (ans / 60 + 1 ) * b; if (d > cnt) { printf ("gua!\n" ); } else { printf ("ok\n" ); } } } return 0 ; }
题意:给一个字符串S,和S一个子序列F。求最短的S的子串T,使F也是T的子序列。
思路:正解是dp(还可以枚举二分卡过去)
dp[i][j]表示S到i,F匹配到第j位的最短长度。
若s[i] != f[j], 则dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1);
若s[i] == f[j],则dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <bits/stdc++.h> using namespace std;const int N = 1e5 + 10 ;int dp[N][108 ];const int INF = 0x3f3f3f3f ;int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); int tt; cin >> tt; while (tt--) { string s, f; cin >> s >> f; int n = s.size (); int m = f.size (); s = '#' + s; f = '#' + f; for (int i = 0 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { dp[i][j] = INF; } } dp[0 ][0 ] = 0 ; int pos = 0 ; for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { if (s[i] == f[j]) { dp[i][j] = min (dp[i][j], dp[i - 1 ][j - 1 ] + 1 ); } else { dp[i][j] = min (dp[i][j], dp[i - 1 ][j] + 1 ); } } if (dp[pos][m] > dp[i][m]) { pos = i; } } for (int i = pos - dp[pos][m] + 1 ; i <= pos; i++) { cout << s[i]; } cout << "\n" ; } return 0 ; }
题意:用刷子刷长度为n的墙,每次用一种颜色刷连续的长度为k的一段,后刷的颜色会覆盖前刷的颜色。问给定结果,最小的刷墙次数。
思路:容易想到,如果结果中根本没有长度不小于k的一段颜色相同,那么不可能刷出来,否则都可以刷出这个结果。
我们发现只要有一段长度大于等于k,就一定能刷出来,所以直接从第一个连续段开始,从前往后刷就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <bits/stdc++.h> using namespace std;#define int long long const int N = 1e6 + 10 ;int a[N];int b[N];signed main () { int t; scanf ("%lld" , &t); while (t--) { int n, m, k; scanf ("%lld%lld%lld" , &n, &m, &k); for (int i = 1 ; i <= n; i++) { b[i] = 0 ; scanf ("%lld" , &a[i]); } int cnt = 0 ; a[0 ] = -1 ; for (int i = 1 ; i <= n; i++) { if (a[i] != a[i - 1 ]) { b[++cnt] += 1 ; } else { b[cnt] += 1 ; } } if (a[1 ] == a[n] && cnt != 1 ) { b[1 ] += b[cnt]; cnt -= 1 ; } int flag = 0 ; int sum = 0 ; for (int i = 1 ; i <= cnt; i++) { if (b[i] >= k) { flag = 1 ; } sum += ceil (b[i] * 1.0 / k); } if (flag == 0 ) { printf ("-1\n" ); } else { printf ("%lld\n" , sum); } } return 0 ; }
思路:这题题意读着很难受,做不出来大概率是因为没读懂题QAQ
本题主要难点就是搜索出满足约束的答案。容易发现,如果某个地方对应的是G,那么我们可以完全不管这个地方。然后我们查看每个数字对应的’P’,’B’个数。如果一个数字没有对应的’P’,’B’,意味着他在搜索时可以随便拿,没有数量限制。如果一个数字对应的全都是’P’(假设k个),那么意味着它至少出现k次。如果一个数字既有’P’(k个)也有’B’,说明这个数字要刚好出现k次。同时,最后搜索结果要满足等式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 #include <bits/stdc++.h> using namespace std;const int N = 11 ;char a[11 ], b[11 ];vector<int > v[11 ]; int num[N];int vis[N];char c[N];const int INF = 0x3f3f3f3f ;int cnt = 0 ;char ans[1000000 + 10 ][N];void dfs (int x) { if (x == 9 ) { for (int i = 0 ; i < 10 ; i++) { if (num[i] > 0 && num[i] < 1e4 ) { return ; } } int z = (c[1 ] - '0' ) * 10 + c[2 ] - '0' ; int x = (c[4 ] - '0' ) * 10 + c[5 ] - '0' ; int m = (c[7 ] - '0' ) * 10 + c[8 ] - '0' ; if (z + x != m) { return ; } cnt += 1 ; for (int i = 1 ; i <= 8 ; i++) { ans[cnt][i] = c[i]; } return ; } if (b[x] == 'G' ) { dfs (x + 1 ); return ; } for (int i = 0 ; i < 10 ; i++) { if (vis[i] == 0 && num[i] == 0 || i == a[x] - '0' ) { continue ; } num[i] -= 1 ; c[x] = i + '0' ; dfs (x + 1 ); num[i] += 1 ; } } int main () { cin >> a + 1 >> b + 1 ; for (int i = 0 ; i < 10 ; i++) { num[i] = 1e5 ; vis[i] = 1 ; } for (int i = 1 ; i <= 8 ; i++) { if (b[i] == 'G' ) { c[i] = a[i]; continue ; } v[a[i] - '0' ].push_back (i); } for (int i = 0 ; i < 10 ; i++) { if (v[i].size () == 0 ) { continue ; } int sum = 0 ; for (auto t : v[i]) { if (b[t] == 'P' ) { sum++; } else { vis[i] = 0 ; } } num[i] = sum; } dfs (1 ); cout << cnt << "\n" ; for (int i = 1 ; i <= cnt; i++) { cout << ans[i] + 1 << "\n" ; } return 0 ; }
题意:m个排行榜,只要有一个排行榜中a比b前,那么a就比b好。(a比b好和b比a好可以同时成立)且如果a比b好,b比c好,那么a比c好。求每所学校好于多少所学校。
思路:每一个排行榜相邻两点建图的话是一条链状DAG,如果多个排行榜一起建图的话就会形成很多环,容易发现环上的点是共享答案的。因此可以缩成一个点。可以证明,缩完点之后的DAG也是链状的,因此可以直接求得。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #include <bits/stdc++.h> using namespace std;const int N = 5e5 + 10 ;int n, m, b;vector<int > e[N]; int dfn[N], low[N], tot;stack<int > s; int scc[N], siz[N], cnt;int din[N], dout[N];int a[N];int num[N];vector<int > v[N]; void tarjan (int x) { dfn[x] = low[x] = ++tot; s.push (x); for (auto y : e[x]) { if (!dfn[y]) { tarjan (y); low[x] = min (low[x], low[y]); } else if (!scc[y]) { low[x] = min (low[x], dfn[y]); } } if (dfn[x] == low[x]) { ++cnt; while (1 ) { int y = s.top (); s.pop (); scc[y] = cnt; ++siz[cnt]; if (x == y) { break ; } } } } void dfs (int x, int fa) { for (int t : v[x]) { if (t == fa) { continue ; } dfs (t, x); siz[x] += siz[t]; } } int main () { scanf ("%d%d" , &n, &m); for (int j = 1 ; j <= m; j++) { for (int i = 1 ; i <= n; i++) { scanf ("%d" , &a[i]); if (i > 1 ) { e[a[i - 1 ]].push_back (a[i]); } } } for (int i = 1 ; i <= n; i++) { if (!dfn[i]) { tarjan (i); } } for (int i = 1 ; i <= n; i++) { for (auto t : e[i]) { if (scc[t] != scc[i]) { e[scc[i]].push_back (scc[t]); } } } for (int i = 1 ; i <= cnt; i++) { siz[i] += siz[i - 1 ]; } for (int i = 1 ; i <= n; i++) { printf ("%d " , siz[scc[i]] - 1 ); } printf ("\n" ); return 0 ; }
思路:
设dp[i]为1-i的得分, 划分中没有包含的子串)dp[i]=dp[i−1](划分中没有包含i的子串)+∑j dp[i−len(tj)]∗val[tj] 我们可以发现,不同长度的t最多只有 ∑t 个,所以AC自动机压缩完路径后跳fail指针最多不超过 ∑t 个,直接AC自动机+转移即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 #include <bits/stdc++.h> using namespace std;const int N = 2e5 + 5 ;int ch[N][26 ];int idx;int ne[N];char str[N], s[N];int e[N], g[N];const int mod = 998244353 ;int fuck[N];int dp[N];void insert (int x) { int p = 0 ; int len = strlen (s + 1 ); for (int i = 1 ; i <= len; i++) { int j = s[i] - 'a' ; if (!ch[p][j]) { ch[p][j] = ++idx; } p = ch[p][j]; } e[p] = x; g[p] = len; } void build () { queue<int > q; for (int i = 0 ; i < 26 ; i++) { if (ch[0 ][i]) { q.push (ch[0 ][i]); } } while (!q.empty ()) { int u = q.front (); q.pop (); if (e[u]) { fuck[u] = u; } else { fuck[u] = fuck[ne[u]]; } for (int i = 0 ; i < 26 ; i++) { int v = ch[u][i]; if (v) { ne[v] = ch[ne[u]][i]; q.push (v); } else { ch[u][i] = ch[ne[u]][i]; } } } } int main () { scanf ("%s" , str + 1 ); int m; scanf ("%d" , &m); int ans; for (int i = 1 ; i <= m; i++) { scanf ("%s%d" , s + 1 , &ans); insert (ans); } build (); dp[0 ] = 1 ; int n = strlen (str + 1 ); for (int i = 1 , u = 0 ; i <= n; i++) { dp[i] = dp[i - 1 ]; u = ch[u][str[i] - 'a' ]; for (int j = fuck[u]; j; j = fuck[ne[j]]) { if (g[j] <= i) { dp[i] += 1ll * dp[i - g[j]] * e[j] % mod; dp[i] %= mod; } } printf ("%d " , dp[i]); } return 0 ; }