文章目录
- A
- 题目
- AC Code:
- B
- 题目
- AC Code:
- C
- 题目
- AC Code:
- D
- 题目
- AC Code:
- E
- 题目
- AC Code:
A
题目
这个 A 题为什么是平时 B 题的分值?
统计每一个字母的出现次数,找到出现次数为 1 1 1 的字母,输出它的位置,完事。
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
string s;
int cnt[100100];int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> s;int len = s.size();for (int i = 0; i < len; i++) {cnt[s[i] - 'a']++;}for (int i = 0; i < 26; i++) {if (cnt[i] == 1) {for (int j = 0; j < len; j++) {if (s[j] == i + 'a') {cout << j + 1;return 0;}}}}return 0;
}
B
题目
对于每一个寻问,找到这两个数的位置,输出值较小的那个数的坐标,完事。
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
int n, q;
int p[100100];int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++) {cin >> p[i];}cin >> q;while (q--) {int l ,r;cin >> l >> r;int idx1, idx2;for (int i = 1; i <= n; i ++) {if (p[i] == l) idx1 = i;if (p[i] == r) idx2 = i;}cout << (idx1 < idx2 ? l : r) << '\n';}return 0;
}
C
题目
此题容易被误解成并查集,但是第一个样例就可以 hack 普通并查集做法。
我们直接记录原来字串中那些字母要被替换成另外的字母,一开始所有字母都要被替换成自己,每出现一个替换关系,比如把 a a a 替换成 b b b,我们就寻找原来要替换成 a a a 的字母,将其替换成 b b b,最后输出时在原字母中进行替换即可。
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
int n, q;
string s;
int f[30];int main() {
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);cin >> n >> s;for (int i = 0; i < 26; i++) f[i] = i;cin >> q;while (q--) {string u, v;cin >> u >> v;int a = u[0] - 'a', b = v[0] - 'a';for (int i = 0; i < 26; i++) if (f[i] == a) f[i] = b;}for (int i = 0; i < n; i ++) cout << char('a' + f[s[i] - 'a']);return 0;
}
D
题目
对于一个完全平方数,我们将其分解质因数,每一个质因数的个数一定是偶数,这个不难理解。
那么如果我们将一个完全平方数乘上另一个完全平方数,结果是完全平方数,这个应该也在你的理解范围里。
根据上一个定理,我们可以推导出:如果一个完全平方数除以另一个完全平方数,如果结果是整数,那么结果也是一个完全平方数。
现在,关键的定理来了:
如果两个数 a a a 和 b b b,他们可以分解为 k ⋅ p k\cdot p k⋅p 和 l ⋅ q l \cdot q l⋅q,其中 k , p , l , q k,p,l,q k,p,l,q 为整数,且 p p p 和 q q q 为完全平方数, p p p 和 q q q 尽可能大,如果 a ⋅ b a\cdot b a⋅b 为完全平方数,那么 k k k 等于 l l l。
让我们证明一下,对于结果,除以 p p p 和 q q q 后,剩下 k ⋅ l k\cdot l k⋅l,那么结果一定是一个完全平方数,这个定理可以根据上面说的推导出来。而 k k k 和 l l l 不是完全平方数,只能说明 k k k 等于 l l l。请自行理解,如果 k k k 不等于 l l l,哪里会产生矛盾。
我们就可以预处理出每一个数分解掉所有可被分解的完全平方数,统计剩下每一个数字的个数。对于每一个数字,可以与其他和这个数字相等的组成一对,加上其他数字的个数。对于 0 0 0,加上 2 ( n − 1 ) 2(n-1) 2(n−1),因为这个 0 0 0 可以与其他数字组成一组,其他数字也可以与这个数字组成一组。设一共有 x x x 个 0 0 0,最后答案要减去 x ( x − 1 ) x(x-1) x(x−1),因为 0 0 0 与 0 0 0 之间的连边被重复算了。最后答案除以 2 2 2,去掉重复算的组数,输出就完事了。
特别注意:答案要开长整形!
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
long long n, a[200100];
long long ans;
map<long long, long long> cnt;int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (long long i = 1; i <= n; i ++) cin >> a[i];for (long long i = 1; i <= n; i ++) {long long tmp = sqrt(a[i]);bool vis = 1;while (vis) {vis = 0;for (long long j = 2; j <= tmp; j++) {if (a[i] % (j * j) == 0) {a[i] /= (j * j);vis = 1;break;}}}}for (long long i = 1; i <= n; i ++) {cnt[a[i]]++;}for (long long i = 1; i <= n; i ++) {if (a[i] == 0) ans += (n - 1) * 2;else ans += cnt[a[i]] - 1;}ans -= cnt[0] * (cnt[0] - 1);cout << ans / 2;return 0;
}
E
题目
要算每一个点到终点的时间,可不可以把所有边逆转方向,再从终点跑一遍最短路?
我们得到在时间限制下每一条路线最后一班车的时间,再跑一遍迪杰斯特拉算法,终点的时间为无穷大,然后让每一个点到达的时间尽量大,去找下一条边时,要乘坐时间不能超过当前时间的列车。如果第一班车都比当前时间晚,就不能乘坐。如果没有跑到一个点,就说明这个点不能到达终点。
注意:要开长整形,由于精度问题,建议全开长整形。
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
long long n, m;
struct edge{long long u, v, w, l, d, k, nxt;long long get(long long t) {if (t < l + w) return -1;return l + min(k - 1, (t - l - w) / d) * d;}
};
edge ed[400100];
long long edcnt, head[200100];
void addedge(long long l, long long d, long long k, long long u, long long v, long long w){edcnt++;ed[edcnt].u = u;ed[edcnt].v = v;ed[edcnt].w = w;ed[edcnt].l = l;ed[edcnt].d = d;ed[edcnt].k = k;ed[edcnt].nxt = head[u];head[u] = edcnt;
}
struct node {int x;long long dis;node(int x_, long long dis_) {x = x_;dis = dis_;}
};
bool operator <(node a, node b) {return a.dis < b.dis;
}long long dis[514114];
long long ans[200100];
void dijkstra() {priority_queue<node> pq;pq.push(node(n, 0x7f7f7f7f7f7f7f7f));while (!pq.empty()) {node now = pq.top();pq.pop();if (ans[now.x] > now.dis) continue;for (int i = head[now.x]; i; i = ed[i].nxt) {int v = ed[i].v;long long t = ed[i].get(now.dis);if (t != -1 && ans[v] < t) {ans[v] = t;pq.push(node(v, t));}}}
}
int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;for (int i = 1; i <= m; i++) {long long l, d, k, c, a, b;cin >> l >> d >> k >> c >> a >> b;addedge(l, d, k, b, a, c);}for (long long i = 1; i <= n; i++) {ans[i] = -1;}ans[n] = 0x7f7f7f7f7f7f7f7f;dijkstra();for (int i = 1; i < n; i++) {if (ans[i] != -1) cout << ans[i] << '\n';else cout << "Unreachable\n";}return 0;
}