QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#622190 | #5311. Master of Both | Grunray | WA | 79ms | 63980kb | C++20 | 14.5kb | 2024-10-08 20:11:18 | 2024-10-08 20:11:18 |
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 = 1e6 + 50;
ll n, m;
ll ans[35][35];
//ll pos[N];
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) if (j != c)ans[j][c] += exist[nex[p][j]];
//pos[p][c]++;
p = nex[p][c];
++exist[p];
}
done[p] = 1; // 记录成为一个[词]
}
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;
int query(string s) {
ll res = 0;
for (int i = 0; i < s.length(); i++) {
int u = s[i] - 'a' + 1;
res += ans[u][0];
for (int j = 0; j < i; j++) {
int v = s[j] - 'a' + 1;
res += ans[u][v];
}
}
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;
}
详细
Test #1:
score: 100
Accepted
time: 1ms
memory: 5912kb
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: 0
Accepted
time: 0ms
memory: 57512kb
input:
100 100 spkfvrbkfsspmnlgrdojwdqutknvzejorqxsmfgbfrhpxkrrtravhmxenjrzypkxounrbantpkaezlcnudjmwxpgqakfoxcmdjcygujdtpluovbisxmklkzzuuyziapzyrszcggjkzrwmtyolnbobubbezdwmumyzyhaogiiolictzjpxbyaamecytpnyzxlumxjkzyfavxlzdwtgrxtqcnddzfocznitlaxlpcceuelqlbmyzetlpaivxnuvuctsbjbaulmbmkangqahpdojqimvmcugjeczkgx...
output:
2368 2693 2179 2466 2435 2370 2604 2468 2335 2268 2686 2781 2538 2208 2386 2539 2728 2383 2248 2372 2446 2266 2290 2688 2602 2515 2634 2558 2598 2632 2763 2255 2557 2579 2367 2516 2676 2273 2429 2556 2576 2635 2422 2829 2362 2552 2377 2261 2603 2516 2298 2282 2520 2333 2505 2287 2261 2476 2791 2328 ...
result:
ok 100 numbers
Test #3:
score: -100
Wrong Answer
time: 79ms
memory: 63980kb
input:
500000 5 ru x tb s e w e m l b g zr jp h js xk fjwtk wtkem o ev a a x sy dh y kkdcxfr hgq j k xr s cvwbrlk u u x wtvgef dzxsk qv gxl g m rpl ldp q lc dk g k im o yhn z a knc tyv mz ak qdhq c niw o j heu w g e kt n inqt i al q ebphky sv m mry oj cl j r sf vpd u rio sfkg m el s zs g o e njp r xczcm gh...
output:
1779013680 1811066236 1753493718 1821661336 1795055750
result:
wrong answer 1st numbers differ - expected: '61908555824', found: '1779013680'