QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#622057 | #5311. Master of Both | Timeless123 | RE | 0ms | 5748kb | C++17 | 14.5kb | 2024-10-08 19:41:48 | 2024-10-08 19:41:49 |
Judging History
answer
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define bit(x) (1LL << (x))
#define lowbit(x) (x & -x)
#define sq(x) ((x) * (x))
#define rep(a, b, c, d) for (int a = (b); a <= (c); a += (d))
#define fep(a, b, c, d) for (int a = (b); a >= (c); a -= (d))
using ll = long long;
using unll = unsigned long long;
/*--int128--*/
//inline __int128 read() {//__int128模板
// __int128 x = 0, f = 1;
// char ch = getchar();
// while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
// while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
// return x * f;
//}
//inline void print(__int128 x) {
// if (x < 0) { putchar('-'); x = -x; }
// if (x > 9) print(x / 10);
// putchar(x % 10 + '0');
//}
/*--fast read--*/
template<typename T> T read() {
T X = 0; bool flag = true; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') flag = false; ch = getchar(); }
while (ch >= '0' && ch <= '9') { X = (X << 1) + (X << 3) + ch - '0'; ch = getchar(); }
if (flag) return X;
return ~(X - 1);
}
template<typename T> void write(T X) {
if (X < 0) { putchar('-'); X = ~(X - 1); }
int s[100], top = 0;
while (X) { s[++top] = X % 10; X /= 10; }
if (!top) s[++top] = 0;
while (top) putchar(s[top--] + '0');
}
/*--const--*/
const int INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3f;
const long long MODE = 998244353;
const int dx[] = { 1, 0,-1, 0, 1, 1,-1,-1 };
const int dy[] = { 0,-1, 0, 1, -1, 1,-1, 1 };
const double eps = 1e-8;
double Pi = acos(-1.0);
/*--math--*/
long long qpow(long long x, long long y) {
x %= MODE;
long long res = 1;
while (y) {
if (y & 1) res = res * x % MODE;
x = x * x % MODE;
y >>= 1;
}
return res;
}
long long gcd(long long a, long long b) { // 最大公约数
while (b ^= a ^= b ^= a %= b)
;
return a;
}
long long lcm(long long a, long long b) { // 最小公倍数
return a / gcd(a, b) * b;
}
/*------------CODE------------*/
// int months[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
//priority_queue<ll> pq;//这是一个大根堆q
//priority_queue<int, vector<int>, greater<int> >q;//这是一个小根堆q
//priority_queue<ll, vector<ll>, greater<ll> >pq; // 小根
const long long N = 2e6 + 50;
const long long M = 2e6 + 50;
ll n, m;
ll ans[30][30];
ll pos[30][30];
struct STRING
{
// 哈希
struct HASHE { // 下标从1开始
const int Pri = 13331;
unll p[N], h[N];
unll val = 0;
// 求一个串的哈希值相当于求前缀和
unll init(string str) {
p[0] = 1; h[0] = 0;
int len = str.length();
for (int i = 1; i < len; i++) {
p[i] = p[i - 1] * Pri;
h[i] = h[i - 1] * Pri + str[i];
}
val = h[len - 1];
return val; // 当前串的哈希值
}
// 求子串的哈希值相当于求区间和
unll getSubHash(int l, int r) { return h[r] - h[l - 1] * p[r - l + 1]; }
bool isSameSub(int l1, int r1, int l2, int r2) { return getSubHash(l1, r1) == getSubHash(l2, r2); }
};
struct Binary_HASHE
{
unll lh[N], rh[N], p[N];
const ll Pri = 131ll;
char s[N], c[N];
unll pos;
//ll len;
ll lhget(ll l, ll r) {
return ((lh[r] - lh[l - 1] * p[r - l + 1] % MODE + MODE) % MODE + MODE) % MODE;
}
ll rhget(ll l, ll r) {
return ((rh[l] - rh[r + 1] * p[r - l + 1] % MODE + MODE) % MODE + MODE) % MODE;
}
ll cal(ll x, ll d) {
if (x >= d)
return rhget(pos + x - d, pos + x - 1);
else {
ll res1 = rhget(pos, pos + x - 1);
ll res2 = lhget(pos + x, pos + d - 1);
return (res1 * p[d - x] % MODE + res2) % MODE;
}
}
char Getchar(ll x, ll d) {
if (x >= d) return s[pos + x - d];
else return s[pos + d - 1];
}
bool check(ll x, ll y) {
ll l = 0, r = n - pos;
while (l < r) {
ll mid = (l + r + 1) / 2;
ll p = cal(x, mid);
ll q = cal(y, mid);
if (p == q)
l = mid;
else
r = mid - 1;
}
l++;
char _x = Getchar(x, l);
char _y = Getchar(y, l);
return _x > _y;
}
};
// 字典树
struct Trie {
int nex[N][65], cnt;
int exist[N]; // 该结点结尾的[词]出现次数是多少
bool done[N]; // 记录是否为一个[词]
bool vis[N]; // 记录该[词]是否被访问
void init() {
for (int i = 0; i <= cnt; i++) for (int j = 0; j < 65; j++) nex[i][j] = 0;
for (int i = 0; i <= cnt; i++) exist[i] = 0;
cnt = 0;
}
int getAscii(char ch) { // A-Z a-z 0-9
int ascii = 0;
if (isupper(ch)) ascii = int(ch - 'A');
else if (islower(ch)) ascii = int(ch - 'a' + 26);
else if (isdigit(ch)) ascii = int(ch - '0' + 52);
return ascii;
}
void insert(string s) { // 插入[词]
int p = 0, len = s.length();
for (int i = 0; i < len; i++) {
int c = getAscii(s[i]);
if (!nex[p][c]) nex[p][c] = ++cnt; // 如果没有,就添加结点
p = nex[p][c];
++exist[p];
}
done[p] = 1; // 记录成为一个[词]
}
void newInsert(string s) {
int p = 0, len = s.length();
for (int i = 0; i < len; i++) {
int c = s[i] - 'a' + 1;
if (!nex[p][c]) nex[p][c] = ++cnt; // 如果没有,就添加结点
rep(j, 0, 26, 1) ans[j][c] += pos[p][j];
pos[p][c]++;
p = nex[p][c];
++exist[p];
}
done[p] = 1; // 记录成为一个[词]
}
void query(string s) {
}
int find(string s) { // 查找[词]
int p = 0, len = s.length();
for (int i = 0; i < len; i++) {
int c = getAscii(s[i]);
if (!nex[p][c]) return 0;
p = nex[p][c];
}
if (done[p]) return exist[p]; // 有这个[词]
return 0; // 没有这个[词]
}
int findUnique(string s) { // 查找[词],并且判断该[词]是否访问过
int p = 0, len = s.length();
for (int i = 0; i < len; i++) {
int c = getAscii(s[i]);
if (!nex[p][c]) return 0;
p = nex[p][c];
}
if (done[p]) { // 有这个[词]
if (vis[p]) return -1; // 重复访问
vis[p] = true;
return exist[p];
}
return 0;
}
};
// 维护异或的字典树
//给定一棵n点的带权树,结点下标1-n。寻找树中找两个结点,求最长的异或路径。
//异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
struct xorTrie {
vector<pair<int, long long> >adj[N];
int cnt = 0, tot = 1, res = 0;
int dis[N], ch[N << 5/*N * 32*/][2];
void insert(int x) {
for (int i = 30, u = 1; i >= 0; --i) {
int c = ((x >> i) & 1); // 二进制一位一位向下取
if (!ch[u][c]) ch[u][c] = ++tot;
u = ch[u][c];
}
}
int get(int x) {
int ans = 0;
for (int i = 30, u = 1; i >= 0; --i) {
int c = ((x >> i) & 1);
if (ch[u][c ^ 1]) { // 如果能向和当前位不同的子树走,就向那边走
u = ch[u][c ^ 1];
ans |= (1 << i);
}
else u = ch[u][c];
}
return res = max(res, ans); // 更新答案
}
void add(int u, int v, int w) { adj[u].push_back({ v, w }); }
void dfs(int u, int fa) {
insert(dis[u]);
get(dis[u]);
for (auto it : adj[u]) { // 遍历子节点
int v = it.first;
long long w = it.second;
if (v == fa) continue;
dis[v] = dis[u] ^ w;
dfs(v, u);
}
}
};
// 前缀函数
// 查找:字符串s, i from 0 to sub.size()-1 形成的子串 是否 有相等的真前缀和真后缀
// 有的话,长度是pi[i]
vector<int> prefix_function(string s) {
int len = (int)s.length();
vector<int> pi(len); // 前缀
for (int i = 1; i < len; i++) {
int j = pi[i - 1];
while (j > 0 && s[i] != s[j]) j = pi[j - 1];
if (s[i] == s[j]) j++;
pi[i] = j;
}
return pi;
}
int getMinPeriod(string s) {
vector<int>pi = prefix_function(s);
int len = s.length();
if (!(len % (len - pi[len - 1]))) return len - pi[len - 1];
else return len;
}
// KMP
// 在字符串中查找子串的位置
vector<int> KMP(string text, string pattern) {
string cur = pattern + '#' + text; // cur = sub + str
int sz1 = text.size(), sz2 = pattern.size();
vector<int> kmp;
vector<int> pi = prefix_function(cur);
for (int i = sz2 + 1; i <= sz1 + sz2; i++) {
if (pi[i] == sz2) kmp.push_back(i - 2 * sz2);
}
return kmp;
}
// 统计每个前缀出现的次数
vector<int> count_occurrences(vector<int> pi, int len) {
vector<int> ans(len + 1);
for (int i = 0; i < n; i++)
ans[pi[i]]++;
for (int i = n - 1; i > 0; i--)
ans[pi[i - 1]] += ans[i];
for (int i = 0; i <= n; i++)
ans[i]++;
return ans;
}
// 最小表示法
ll minn_show(vector<ll> sec) {
ll k = 0, i = 1, j = 2;
// 破环成链
rep(i, 0, n - 1, 1) sec[n + i] = sec[i];
while (k < n && i < n && j < n) {
for (k = 0; k < n && sec[(i + k) % n] == sec[(j + k) % n]; k++)
;
sec[(i + k) % n] > sec[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
if (i == j) i++;
}
return min(i, j);
}
struct AC {
int tr[N][26], tot;
int e[N], fail[N];
void insert(string s) {
int u = 0;
for (int i = 0; i < s.length(); i++) {
if (!tr[u][s[i] - 'a']) tr[u][s[i] - 'a'] = ++tot; // 如果没有则插入新节点
u = tr[u][s[i] - 'a']; // 搜索下一个节点
}
e[u]++; // 尾为节点 u 的串的个数
}
void build() {
queue<int> q;
for (int i = 0; i < 26; i++)
if (tr[0][i]) q.push(tr[0][i]);
while (q.size()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; i++) {
if (tr[u][i]) {
fail[tr[u][i]] =
tr[fail[u]][i]; // fail数组:同一字符可以匹配的其他位置
q.push(tr[u][i]);
}
else tr[u][i] = tr[fail[u]][i];
}
}
}
int query(string s) {
int u = 0, res = 0;
for (int i = 0; i < s.length(); i++) {
u = tr[u][s[i] - 'a']; // 转移
for (int j = u; j && e[j] != -1; j = fail[j])
res += e[j], e[j] = -1;
}
return res;
}
};
struct SAM {
// 每次End 是代表新产生的位置的作用点
// 新创建的数组要清空
//const int Max = ((1e5 + 5) * 2); // M节点数量,字符串长度的两倍
int ch[M][30], mxlen[M], par[M], tp[M];
int End, tot;
int siz[M];
int newnod() {
tot++;
mxlen[tot] = par[tot] = 0;
memset(ch[tot], 0, sizeof(ch[tot]));
siz[tot] = 0;
return tot;
}
void clear() { // 1为root
tot = 0;
End = newnod();
}
void extend(int c) {
int p = End; End = newnod();
mxlen[End] = mxlen[p] + 1;
siz[End] = 1;
for (; p && !ch[p][c]; p = par[p]) ch[p][c] = End;
if (!p) par[End] = 1;
else {
int q = ch[p][c];
if (mxlen[p] + 1 == mxlen[q]) par[End] = q;
else {
int nq = newnod(); mxlen[nq] = mxlen[p] + 1; // nq是新产生的分叉点
memcpy(ch[nq], ch[q], sizeof(ch[q]));
par[nq] = par[q], par[End] = par[q] = nq;
for (; ch[p][c] == q; p = par[p]) ch[p][c] = nq;
}
}
}
void build() {//倒叙循环满足拓扑
static int cnt[M];
rep(i, 0, tot + 1, 1) cnt[i] = 0;
rep(i, 1, tot + 1, 1) cnt[mxlen[i]]++;
rep(i, 1, tot + 1, 1) cnt[i] += cnt[i - 1];
fep(i, tot, 1, 1) tp[cnt[mxlen[i]]--] = i;
}
};
// 回文树查询回文子串出现次数
struct PAM {
int sz, tot, last;
int cnt[N], ch[N][26], len[N], fail[N];
char s[N];
int node(int l) { // 建立一个新节点,长度为 l
sz++;
memset(ch[sz], 0, sizeof(ch[sz]));
len[sz] = l;
fail[sz] = cnt[sz] = 0;
return sz;
}
void clear() { // 初始化
sz = -1;
last = 0;
s[tot = 0] = '$';
node(0); node(-1);
fail[0] = 1;
}
int getfail(int x) { // 找后缀回文
while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
return x;
}
void insert(char c, int i) { // 建树
s[++tot] = c;
int now = getfail(last);
if (!ch[now][c - 'a']) {
int x = node(len[now] + 2);
fail[x] = ch[getfail(fail[now])][c - 'a'];
ch[now][c - 'a'] = x;
}
last = ch[now][c - 'a'];
//if (i > n)// 若破链成环
cnt[last]++;
}
long long solve() {
long long ans = 0;
for (int i = sz; i >= 0; i--) {
cnt[fail[i]] += cnt[i];
}
for (int i = 2; i <= sz; i++) { // 更新答案
//if (len[i] > n) continue;// 若破链成环
ans = (ans + (((1ll) * len[i] * cnt[i]) % MODE) * cnt[i]) % MODE;
}
return ans;
}
};
//Lyndon 分解
struct Lyndon
{
//s 的字典序严格小于 s 的所有后缀的字典序,我们称 s 是Lyndon 串。
//例,a,b,ab,aab,abb,ababb,abcd 都是 Lyndon 串
vector<int> duval_getRightPoint(string const& s) { // 下标从 1 开始
int len = s.size(), i = 1;
vector<string> lyndon;
vector<int> right_point;
while (i < len) {
int j = i + 1, k = i;
while (j < len && s[k] <= s[j]) {
if (s[k] < s[j]) k = i;
else k++;
j++;
}
while (i <= k) {
lyndon.push_back(s.substr(i, j - k)); // Lyndon串
i += j - k;
right_point.push_back(i);
}
}
//return lyndon;
return right_point;
}
//求这个字符串的所有前缀字符串中的最大字典序子串
//子串的左端点就是数组 l[]
//可以证明其右端点就是 子串最右端 即 i
vector<int> duval_getMaxOrderSubstringLeftPoint(string const& s) {
int len = s.size(), i = 1;
vector<int>l(len + 5);
while (i < len) {
int j = i + 1, k = i;
if (!l[i]) l[i] = i;
//cout << i << ' ';
while (j < len && s[k] >= s[j]) {
if (!l[j]) l[j] = i;
if (s[k] == s[j]) k++;
else k = i;
j++;
}
while (i <= k) i += j - k;
}
return l;
}
// 最小表示法
string minCyclicString(string s) {
s += s;
int len = s.size();
int i = 0, ans = 0;
while (i < len / 2) {
ans = i;
int j = i + 1, k = i;
while (j < len && s[k] <= s[j]) {
if (s[k] < s[j]) k = i;
else k++;
j++;
}
while (i <= k) i += j - k;
}
return s.substr(ans, len / 2);
}
};
};
STRING::Trie trie;
string str;
ll cnt[30];
int query(string s) {
rep(i, 0, 25, 1) cnt[s[i] - 'a' + 1] = i;
ll res = 0;
rep(i, 0, 25, 1)
rep(j, 0, 25, 1)
if (cnt[i] > cnt[j])
res += ans[i][j];
return res;
}
void solve() {
cin >> n >> m;
rep(i, 1, n, 1) {
cin >> str;
str += 'a' - 1;
trie.newInsert(str);
}
rep(i, 1, m, 1) {
cin >> str;
cout << query(str) << '\n';
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("wrt.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
signed T = 1;
//scanf("%d", &T);
//cin >> T;
while (T--) {
solve();
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 0ms
memory: 5748kb
input:
5 3 aac oiputata aaa suikabudada aba abcdefghijklmnopqrstuvwxyz qwertyuiopasdfghjklzxcvbnm aquickbrownfxjmpsvethlzydg
output:
4 3 4
result:
ok 3 number(s): "4 3 4"
Test #2:
score: -100
Runtime Error
input:
100 100 spkfvrbkfsspmnlgrdojwdqutknvzejorqxsmfgbfrhpxkrrtravhmxenjrzypkxounrbantpkaezlcnudjmwxpgqakfoxcmdjcygujdtpluovbisxmklkzzuuyziapzyrszcggjkzrwmtyolnbobubbezdwmumyzyhaogiiolictzjpxbyaamecytpnyzxlumxjkzyfavxlzdwtgrxtqcnddzfocznitlaxlpcceuelqlbmyzetlpaivxnuvuctsbjbaulmbmkangqahpdojqimvmcugjeczkgx...