A. Ancient Distance
https://ac.nowcoder.com/acm/contest/5669/A
B. Basic Gcd Problem
https://ac.nowcoder.com/acm/contest/5669/B
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
int n, c, m;
int primes[N], cnt; // 存储所有质数
bool st[N]; // 存储每个数是否已被筛掉
void get_primes(int n){ // 线性筛法求素数
st[1] = 1;
for (int i = 2; i <= n; i++) {
if (!st[i]) primes[cnt++] = i;
for (int j = 0; primes[j] <= n / i; j++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
ll qpow(ll a, ll b) {
a %= mod;
ll res = 1;
while (b) {
if (b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int main() {
ios::sync_with_stdio(false);
get_primes(1000000);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &c);
// 如果是素数 直接输出1
if (!st[n]) {
m = 1;
} else {
// 如果不是 则统计质因子的个数
m = 0;
for (int i = 0; i < cnt && primes[i] <= n; i++) {
if (n % primes[i] == 0) {
while (n % primes[i] == 0) {
m++;
n /= primes[i];
}
}
if (!st[n])break;
}
if (n > 1) {
m++;
}
}
printf("%lld\n", qpow(c, m));
}
return 0;
}
C. Count New String · 后缀自动机
https://ac.nowcoder.com/acm/contest/5669/C
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
int pos[N];
namespace Sam { // 后缀自动机
const int M = 2e6 + 10;
const int CHAR_NUM = 10;
// 后缀自动机
struct SAM {
struct state {
int len, link;
vector<int> nxt;
state() { nxt.resize(CHAR_NUM); }
} st[M * 2];
int sz;//自动机的大小
int last;// 未加入下一个字符前最长的前缀(整个串)所属的节点的编号
void init() {
// 创建只有一个初始状态的sam
st[0].len = 0;
st[0].link = -1;
sz = 0;
last = 0;
}
void insert(int c) {
int cur = ++sz;
st[cur].len = st[last].len + 1;
int p = last;
while (p != -1 && !st[p].nxt[c]) {
st[p].nxt[c] = cur;
p = st[p].link;
}
if (p == -1) {
st[cur].link = 0;
} else {
int q = st[p].nxt[c];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = ++sz;//复制
st[clone].len = st[p].len + 1;
st[clone].nxt = st[q].nxt;
st[clone].link = st[q].link;
while (p != -1 && st[p].nxt[c] == q) {
st[p].nxt[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
} sam;
}
using namespace Sam;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
string s;
cin >> s;
s = " " + s;
sam.init();
int n = s.length() - 1;
pos[n + 1] = 0;
stack<int> st;// 单调栈 字符从大到小排列
for (int i = n; i >= 1; i--) {//从后往前遍历
while (!st.empty() && s[st.top()] < s[i]) st.pop();
int k = st.empty() ? n + 1 : st.top();//记下 最大字母的下标 根据坐标寻找插入时对应的后缀自动机的状态
sam.last = pos[k];
for (int j = i; j < k; j++) {
sam.insert(s[i] - 'a');
}
pos[i] = sam.last;
st.push(i);
}
ll ans = 0;
// 根据后缀自动机的性质 以点i为节点的子串的个数 = len[i]-len[link[i]]
for (int i = 1; i <= sam.sz; i++) {
ans += sam.st[i].len - sam.st[sam.st[i].link].len;
}
cout << ans << endl;
return 0;
}
D Dividing Strings
E Eliminate++
F. Finding the Order
https://ac.nowcoder.com/acm/contest/5669/F
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[310][310];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int ac, ad, bc, bd;
scanf("%d%d%d%d", &ac, &ad, &bc, &bd);
if (ac > ad)puts("AB//DC");
else if (ac == ad) {
if (bc > bd)puts("AB//CD");
else puts("AB//DC");
} else puts("AB//CD");
}
return 0;
}
G Geometry Challenge
H. Harder Gcd Problem
https://ac.nowcoder.com/acm/contest/5669/H
优先处理质因子较大的数,因为质因子越大,含有该质因子的数越少
当包含同一个质因子的数的个数有偶数个时,显然可以将这些数俩俩匹配
如果是奇数的话,就是一群配对里出了个单身狗的故事了,
选一个包含了更小的质因子的数,将其与其他同样包含了更小的质因子的数进行匹配
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef pair<int, int> pii;
int n;
vector<int> v[N];// v[i]存放 包含第i个质因子的数
int primes[N], cnt = 0; // 存储所有质数
int st[N], vis[N]; // 存储每个数是否已被筛掉
int Mx[N], Mi[N]; // 质因子最大值 质因子最小值
int id[N];
void get_primes(int n){ // 线性筛法求素数
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt] = i;
id[i] = cnt;
cnt++;
}
for (int j = 0; primes[j] <= n / i; j++) {
st[primes[j] * i] = 1;
if (i % primes[j] == 0) break;
}
}
// 求出所有质因子后 再筛选 将每个数放到自己最大质因子的位置
// 用埃筛直接找也是可以的
for (int i = cnt - 1; i >= 0; i--) {
for (int j = primes[i]; j <= n; j += primes[i]) {
if (!vis[j]) {
vis[j] = 1;
Mx[j] = Mi[j] = primes[i];
} else {
Mi[j] = min(Mi[j], primes[i]);
}
}
}
}
vector<pii> ans;
int sz;
int main() {
ios::sync_with_stdio(false);
get_primes(200000);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 0; i < cnt; i++) {
v[i].clear();
}
ans.clear();
int lim = 0;
for (int i = 2; i <= n; i++) {
v[id[Mx[i]]].push_back(i);
lim = max(lim, Mx[i]);
}
lim = id[lim];
for (int i = lim; i >= 0; i--) {
sz = v[i].size();
if (sz == 1) {
// 抛弃
} else if (sz & 1) {//奇数
sort(v[i].begin(), v[i].end(), [](int a, int b) { // c++14写法
return Mi[a] < Mi[b];
});
int x = v[i][0];
if (Mi[x] != primes[i]) {//下放
v[id[Mi[x]]].push_back(x);
} else {
//抛弃
}
for (int j = 1; j < sz; j += 2) { // 相邻两个进行匹配
ans.push_back({v[i][j], v[i][j + 1]});
}
} else {//偶数
for (int j = 0; j < sz; j += 2) {
ans.push_back({v[i][j], v[i][j + 1]});
}
}
}
sz = ans.size();
printf("%d\n", sz);
for (int i = 0; i < sz; i++) {
printf("%d %d\n", ans[i].first, ans[i].second);
}
}
return 0;
}
I Investigating Legions
J Jumping on the Graph