文章目录
A All with Pairs
题目链接
题目大意
给定n个字符串,字符串s,t的最长相同的前缀后缀为f(s,t)。
大致思路
对所有后缀求hash,用map来存储。然后对一个字符串的每一个前缀求出hash值,对应的map[hash[i]]
就是相同后缀数量。但可能出现重复计数的情况。例如aba
,后缀aba
包含a
,计算a
是多计数了一次。所以要求出nxt
数组,减去重复计数的即可。
完整代码
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 100000 + 10;
int n,nxt[N*10],num[N*10];
ll ans = 0, mod = 998244353;
string a[N];
map<ull, int>pls;
void getkmp(string a)
{
int j = -1;
nxt[0] = -1;
for (int i = 1; i < a.size(); i++)
{
while (j != -1 && a[i] != a[j + 1])j = nxt[j];
if (a[i] == a[j + 1])j++;
nxt[i] = j;
}
}
void Hash(string a)
{
ull t = 0,base=1;
for (int i = a.size() - 1; i >= 0; i--)
{
t = t + (a[i] - 'a' + 1) * base;
base *= 2333;
pls[t]++;
}
}
void getnum(string a)
{
ull t = 0;
for (int i = 0; i < a.size(); i++)
{
t = t * 2333 + (a[i] - 'a' + 1);
num[i] = pls[t];
}
}
void getans(string a)
{
for (int i = 0; i < a.size(); i++)
{
if (nxt[i] != -1)
{
num[nxt[i]] -= num[i];
}
}
for (ll i = 0; i < a.size(); i++)
{
ans = (ans + num[i] * (i+1)*(i+1)) % mod;
}
}
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
read(n);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
Hash(a[i]);
}
for (int i = 1; i <= n; i++)
{
getnum(a[i]);
getkmp(a[i]);
getans(a[i]);
}
printf("%lld\n", ans);
return 0;
}
B Boundary(待补)
C Cover the Tree
题目链接
题目大意
求一棵树的最小链覆盖,并输出每条链的两端节点编号。
大致思路
是个结论题,最小链覆盖是叶子节点数/2向上取整。比赛的时候我不知道怎么去输出结果,队友写出来了,dfs序将叶子节点放入数组,然后i和i+size/2的点匹配。正确性题解是这样解释的
完整代码
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 200000 + 10;
int n, head[N], sumline,du[N];
vector<int>pls;
struct line
{
int nxt, to;
}p[N*10];
void add(int x, int y)
{
p[++sumline] = line{ head[x],y };
head[x] = sumline;
}
void dfs(int f, int u)
{
if (du[u] == 1)pls.push_back(u);
for (int i = head[u]; i; i = p[i].nxt)
{
int to = p[i].to;
if (to == f)continue;
dfs(u, to);
}
}
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
read(n);
for (int i = 1; i <= n - 1; i++)
{
int x, y;
read(x), read(y);
add(x, y), add(y, x);
du[x]++, du[y]++;
}
dfs(0, 1);
if (pls.size() & 1)
pls.push_back(1);
printf("%d\n", pls.size() / 2);
for (int i = 1; i <= pls.size() / 2; i++)
{
printf("%d %d\n", pls[i - 1], pls[i - 1 + pls.size() / 2]);
}
return 0;
}
D Duration
题目链接
题目大意
Given two moments on the same day in the form of
HH:MM:SS, print the number of seconds between the two moments.
给定两个时间,输出他们之间相差的秒数。
大致思路
将时间转换为总秒数,然后输出即可(签到题)
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 200000 + 10;
struct node
{
int h, m, s;
}p[3];
int getnum(node a)
{
return a.h * 3600 + a.m * 60 + a.s;
}
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%02d:%02d:%02d", &p[1].h, &p[1].m, &p[1].s);
scanf("%02d:%02d:%02d", &p[2].h, &p[2].m, &p[2].s);
int num1 = getnum(p[1]);
int num2 = getnum(p[2]);
printf("%d\n", abs(num1 - num2));
return 0;
}
E Exclusive OR(待补)
F Fake Maxpooling
题目链接
题目大意
Given a matrix of size
n×mn\times mn×m and an integer
k{k}k, where
Ai,j=lcm(i,j)A_{i,j} = lcm(i, j)Ai,j=lcm(i,j), the least common multiple of
i{i}i and
j{j}j. You should determine the sum of the maximums among all
k×kk\times kk×k submatrices.
大致思路
先O(n*m)求出A数组
read(n), read(m), read(k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (!a[i][j])
for (int k = 1; k * i <= n && k * j <= m; k++)
a[i*k][j * k] = i * k * j;
然后,利用单调队列来求最大值。最后相加。
完整代码:
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 5000 + 10;
int n, m, k,a[N][N],f[N][N];
int pls[N*2],head,tail;
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
read(n), read(m), read(k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (!a[i][j])
for (int k = 1; k * i <= n && k * j <= m; k++)
a[i*k][j * k] = i * k * j;
for (int i = 1; i <= n; i++)
{
head = tail = 1;
for (int j = 1; j <= m; j++)
{
while (head<tail && a[i][pls[tail-1]] < a[i][j])tail--;
while (head<tail&& j - pls[head] + 1 > k)head++;
pls[tail++] = j;
if (j >= k)
f[i][j - k + 1] = a[i][pls[head]];
}
}
ll ans = 0;
memset(pls, 0, sizeof(pls));
for (int j = 1; j <= m; j++)
{
head = tail = 1;
for (int i = 1; i <= n; i++)
{
while (head <tail && f[pls[tail-1]][j] < f[i][j])tail--;
while (head<tail && i - pls[head] + 1 > k)head++;
pls[tail++] = i;
if (i >= k)
f[i - k + 1][j] = f[pls[head]][j],ans+= f[i - k + 1][j];
}
}
printf("%lld\n", ans);
return 0;
}
比赛的时候直接O(nmlogn)过去了,st表做法:
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 5000 + 10;
int a[N][N], maxm[N][N], n, m, k;
int gcd(int a, int b)
{
return !b ? a : gcd(b, a % b);
}
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
ll ans = 0;
read(n), read(m), read(k);
for (int i = 1; i <= 5000; i++)
for (int j = i; j <= 5000; j++)
{
a[i][j] = i * j / gcd(i, j);
a[j][i] = a[i][j];
maxm[i][j] = a[i][j];
maxm[j][i] = a[j][i];
}
if (k == 1)
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
ans += a[i][j];
printf("%lld\n", ans);
return 0;
}
int lastbase;
for (int base = 1; (1 << base) <= k; base++)
{
int len = (1 << base);
lastbase = len;
for (int i = 1; i + len - 1 <= n; i++)
{
for (int j = 1; j + len - 1 <= m; j++)
{
int maxa = max(maxm[i][j], maxm[i][j + len / 2]);
int maxb = max(maxm[i + len / 2][j], maxm[i + len / 2][j + len / 2]);
maxm[i][j] = max(maxa, maxb);
}
}
}
for (int i = 1; i + k - 1 <= n; i++)
for (int j = 1; j + k - 1 <= m; j++)
{
int maxa = max(maxm[i][j], maxm[i][j + k - lastbase]);
int maxb = max(maxm[i + k - lastbase][j], maxm[i + k - lastbase][j + k - lastbase]);
maxm[i][j] = max(maxa, maxb);
ans += maxm[i][j];
}
printf("%lld\n", ans);
return 0;
}
G Greater and Greater
题目链接
题目大意
Given a sequence
A{A}A of size
n{n}n and a sequence
B{B}B of size
m{m}m, determine the number of subintervals(called
S{S}S) of size
m{m}m in
A{A}A satisfying
∀i∈{1,2,⋯ ,m},Si≥Bi\forall i \in \{1, 2, \cdots, m\}, S_i \ge B_i∀i∈{1,2,⋯,m},Si≥Bi.
对于给定的A数组问有多少个长度为m子数组满足对应的元素均大于等于B[i].
大致思路
将a,b数组排序。用bitset来维护关系,对于b[i],如果bitset[j]为1表示a[j]大于等于b[i].
完整代码
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 200000 + 10;
bitset<150010>ans, res;
pair<int, int>a[N], b[N];
int n, m;
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
read(n), read(m);
for (int i = 1; i <= n; i++)
{
int x; read(x);
a[i] = { x,i };
}
for (int i = 1; i <= m; i++)
{
int x; read(x);
b[i] = { x,i };
}
sort(a + 1, a + 1 + n, greater<pair<int,int> >());
sort(b + 1, b + 1 + m, greater<pair<int,int> >());
int p = 1;
ans.set();
for (int i = 1; i <= m; i++)
{
while (a[p].first >= b[i].first && p <= n)
res.set(a[p++].second);
ans &= (res >> (b[i].second - 1));
}
printf("%d\n", ans.count());
return 0;
}