当前位置: 首页 > news >正文

【字典树 单调栈】P9218 「TAOI-1」Apollo|普及+

本文涉及知识点

C++前缀树(字典树)
C++单调栈

P9218 「TAOI-1」Apollo

题目背景

Execution.

这题原来叫 std::cout << std::fixed << std::setprecision(1) << 6.5 << '\n';

[被当事人删掉的图片.jpg]

【Upd 2023/04/15 21:42】添加了一组 Hack 数据位于 Subtask 2,#13。现在所有赛时的 50\bm{50}50 分提交理论上均只能获得 30\bm{30}30 分。

题目描述

给出 nnn 个十进制小数 a1…ana_1 \dots a_na1an

对于一个 aaa,定义其精度 f(a)f(a)f(a) 表示最小的非负整数 kkk 使得 10k×a10^k\times a10k×a 为整数;对于整数 aaa,定义 f(a)=0f(a) = 0f(a)=0。对于两个十进制小数 a,ba, ba,b,定义 g(a,b)g(a, b)g(a,b) 为对于所有 c∈[min⁡(a,b),max⁡(a,b)]c \in [\min(a,b), \max(a,b)]c[min(a,b),max(a,b)]f(c)f(c)f(c) 的最小值。

对于所有 1≤i≤n1 \leq i \leq n1in,你需要求出 ∑j=1ng(ai,aj)\sum\limits_{j=1}^ng(a_i, a_j)j=1ng(ai,aj) 的值并输出。

定义十进制小数是一个含有整数部分和小数部分的数,其小数部分不为 000。之所以描述得这么愚蠢是因为保证输入的每个数都有小数点,但是好像无论什么写法都会有人提出不满,真是抱歉了。所以还是得看看被当事人删掉的图片。所以我在这里写闲话有人看得到吗。

输入格式

第一行一个整数 nnn

接下来 nnn 行,每行一个十进制小数 aia_iai

输出格式

nnn 行,每行一个整数,分别表示 i=1…ni = 1 \dots ni=1n 对应的答案。

输入输出样例 #1

输入 #1

5
11.4514
11.4778
11.1338
11.1236
11.4789

输出 #1

10
11
9
9
11

输入输出样例 #2

输入 #2

8
1.1145
1.114
1.1145
1.514
1.19198
1.1154
1.114
1.1145

输出 #2

24
21
24
10
18
22
21
24

说明/提示

数据范围

本题采用捆绑测试。

∑i=1nf(ai)=t\sum\limits_{i=1}^n f(a_i) = ti=1nf(ai)=t

  • Subtask 1(15 points):ai≤10a_i \leq 10ai10n≤5n \leq 5n5t≤10t \leq 10t10
  • Subtask 2(15 points):ai≤10a_i \leq 10ai10n≤100n \leq 100n100t≤1000t \leq 1000t1000
  • Subtask 3(20 points):n≤1722n \leq 1722n1722
  • Subtask 4(15 points):ai≤1a_i \leq 1ai1
  • Subtask 5(35 points):无特殊限制。

对于所有数据,0<ai<1090 \lt a_i \lt 10^90<ai<1091≤n≤1051 \leq n \leq 10^51n1051≤t≤3×1061 \leq t \leq 3 \times 10^61t3×106保证 ai\bm{a_i}ai 没有后导 0\color{black}\bm 00,不保证 ai\bm{a_i}ai 互不相同

样例解释

i=1i = 1i=1 为例:

  • j=1j = 1j=1:取 c=11.4514c = 11.4514c=11.4514f(c)=4f(c) = 4f(c)=4
  • j=2j = 2j=2:取 c=11.46c = 11.46c=11.46f(c)=2f(c) = 2f(c)=2
  • j=3j = 3j=3:取 c=11.2c = 11.2c=11.2f(c)=1f(c) = 1f(c)=1
  • j=4j = 4j=4:取 c=11.3c = 11.3c=11.3f(c)=1f(c) = 1f(c)=1
  • j=5j = 5j=5:取 c=11.47c = 11.47c=11.47f(c)=2f(c) = 2f(c)=2

∑j=1ng(a1,aj)=4+2+1+1+2=10\sum\limits_{j=1}^n g(a_1, a_j) = 4 + 2 + 1 + 1 + 2 = 10j=1ng(a1,aj)=4+2+1+1+2=10。对于同一个 jjj,上文给出的所有 ccc,都可能有其它的不同的 ccc 满足 f(c)f(c)f(c) 同样最小。

字典树

不失一般性,a <= b。
如果a和b整数部分不同,c = b的整数部分,即f(c )等于0。
只需要考虑整数部分相同,令小数部分公共前缀为len:
a,0 == len,c = b/10*10,f( c) == 1。如果a或b没小数部分,则f(c)=0f(c)=0f(c)=0
b,len > 0,且两者的小数部分大于len。c=b/10len+1f(c)=len+1c = b / 10^{len+1} f(c)=len+1c=b/10len+1f(c)=len+1
c, len > 0,且a的小数部分长度为len。c=a,即f(c)=lenf(c)=lenf(c)=len。包括a和b的小数部分相等。
总结:c和d整数部分想相同,c的小数部分长度<=d的小数部分长度g(c,d)=c和d小数部分的公共前缀len + c小数部分的长度不是len。
建立若干字典树,整数部分相同的在一颗树,不同的一在一颗字典树。
s[i]是a[i]的小数部分,如果a[i]是整数,则s[i]是空串。
处理a[i]的过程:
cnt[j]记录s中包括前缀s[i][0…j-1]的数量。
ans[i]=∑(cnt)+cnt[0]−xans[i]=\sum(cnt)+cnt[0]-xans[i]=(cnt)+cnt[0]x
x1 = cout(s[j]) 包括前缀s[i]的数量。即s[i]子树的节点数量。
x2 cout(s[j]) 是s[i]的前缀,且s[j]≠s[i]s[j] \neq s[i]s[j]=s[i]。即s[i][0…s[i].长度-2]的叶节点数量。
内存限制512M,很充足。
本题的字典树有如下性质:
一,可以为空。
二,需要记录叶子节点数量。
三,需要记录子节点的数量。
四,需要增加字符串。
五,需要顺序查询节点。

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include<array>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t);return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T = int>
vector<T> Read() {int n;cin >> n;vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}
template<class T = int>
vector<T> ReadNotNum() {vector<T> ret;T tmp;while (cin >> tmp) {ret.emplace_back(tmp);if ('\n' == cin.get()) { break; }}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;AuotToFile();}void writestr(const char* sz) {strcpy(m_p, sz);m_p += strlen(sz);AuotToFile();}inline void write(char ch){*m_p++ = ch;AuotToFile();}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);m_p = puffer;}~COutBuff() {ToFile();}
private:inline void AuotToFile() {if (m_p - puffer > N - 100) {ToFile();}}char  puffer[N], * m_p;
};template<int N = 1'000'000>
class CInBuff
{
public:inline CInBuff() {}inline CInBuff<N>& operator>>(char& ch) {FileToBuf();while (('\r' == *S) || ('\n' == *S) || (' ' == *S)) { S++; }//忽略空格和回车ch = *S++;return *this;}inline CInBuff<N>& operator>>(int& val) {FileToBuf();int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行		return *this;}inline CInBuff& operator>>(long long& val) {FileToBuf();long long x(0); int f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行return *this;}template<class T1, class T2>inline CInBuff& operator>>(pair<T1, T2>& val) {*this >> val.first >> val.second;return *this;}template<class T1, class T2, class T3>inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val);return *this;}template<class T1, class T2, class T3, class T4>inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);return *this;}template<class T = int>inline CInBuff& operator>>(vector<T>& val) {int n;*this >> n;val.resize(n);for (int i = 0; i < n; i++) {*this >> val[i];}return *this;}template<class T = int>vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {*this >> ret[i];}return ret;}template<class T = int>vector<T> Read() {vector<T> ret;*this >> ret;return ret;}
private:inline void FileToBuf() {const int canRead = m_iWritePos - (S - buffer);if (canRead >= 100) { return; }if (m_bFinish) { return; }for (int i = 0; i < canRead; i++){buffer[i] = S[i];//memcpy出错			}m_iWritePos = canRead;buffer[m_iWritePos] = 0;S = buffer;int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);if (readCnt <= 0) { m_bFinish = true; return; }m_iWritePos += readCnt;buffer[m_iWritePos] = 0;S = buffer;}int m_iWritePos = 0; bool m_bFinish = false;char buffer[N + 10], * S = buffer;
};struct CMyTrieNode
{array<CMyTrieNode*, 10> m_child;int m_iCnt = 0;//后代数量int m_iLeafeCnt = 0;//叶子节点数量
};
class CMyTrie {
public:void Add(const char* pStr, const char* pEnd) {auto p = &m_root;for (; pStr < pEnd; pStr++) {p->m_iCnt++;if (nullptr == p->m_child[*pStr - '0']) {p->m_child[*pStr - '0'] = new CMyTrieNode();}p = p->m_child[*pStr - '0'];}p->m_iCnt++;p->m_iLeafeCnt++;}CMyTrieNode m_root;
};class Solution {
public:vector<long long> Ans(const int N, vector<string>& num) {vector<string> str1s, str2s;for (const auto& s : num) {int pos = s.find('.');if (-1 == pos) {str1s.emplace_back(s);str2s.emplace_back("");}else {str1s.emplace_back(s.substr(0, pos));str2s.emplace_back(s.substr(pos + 1));m_tries[str1s.back()].Add(s.data() + pos + 1, s.data() + s.length());}}vector<long long> ans;for (int i = 0; i < str1s.size(); i++) {auto& trie = m_tries[str1s[i]];auto p = &(trie.m_root);long long cur = p->m_iCnt;for (const auto& ch : str2s[i]) {p = p->m_child[ch - '0'];cur += p->m_iCnt;cur -= p->m_iLeafeCnt;}cur -= (p->m_iCnt - p->m_iLeafeCnt);ans.emplace_back(cur);}return ans;}unordered_map<string, CMyTrie> m_tries;
};int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG	ios::sync_with_stdio(0); cin.tie(nullptr);//CInBuff<> in; COutBuff<10'000'000> ob;	int N;cin >> N;vector<string> num(N);for (int r = 0; r < N; r++) {cin >> num[r];}
#ifdef _DEBUG		//printf("N=%d", N);Out(num, ",num=");//Out(a, ",a=");//Out(ab, ",ab=");//Out(par, "par=");//Out(que, "que=");//Out(B, "B=");
#endif // DEBUG		auto res = Solution().Ans(num.size(), num);for (const auto& i : res) {cout << i << "\n";}return 0;
};

单元测试

vector< string > num;TEST_METHOD(TestMethod01){num = { "1","1.2","1.23","1.24" };auto res = Solution().Ans(num.size(), num);AssertV({ 0,3,5,5 }, res);}TEST_METHOD(TestMethod02){num = { "11.4514","11.4778","11.1338","11.1236","11.4789" };auto res = Solution().Ans(num.size(), num);AssertV({ 10,11,9,9,11 }, res);}TEST_METHOD(TestMethod03){num = { "1.1145","1.114","1.1145","1.514","1.19198","1.1154","1.114","1.1145" };auto res = Solution().Ans(num.size(), num);AssertV({ 24,21,24,10,18,22,21,24 }, res);}

单调栈+差分数组

h(d,e)=d小数部分和e小数部分的最长公共前缀长度。
过于复杂,可用于理解单调栈,用于解本题过于复杂。
性质一:ai和aj的整数部分不同,则g(ai,aj)等于0a_i和a_j的整数部分不同,则g(a_i,a_j)等于0aiaj的整数部分不同,g(ai,aj)等于0,故只需要处理整数部分相同的数。
性质二:如果ai等于0或aj等于0→g(ai,aj)等于0a_i等于0或a_j等于0 \rightarrow g(a_i,a_j)等于0ai等于0aj等于0g(ai,aj)等于0。故小数部分为空的数忽略。
实现一(桶排序思想):整数相同的数放到一个桶中,小数部分直接转成字符串放到容器中,升序。
性质三:同一个桶相邻元素d和e相等,则g(d,e)=d的小数部分。
性质四:如果d≠ed \neq ed=e,不失一般性,d < e,d的小数位数是n1,e的小数位数是n2,de的公共前缀长度是n3。如果n3==n1,则g(d,e) =n3,否则g(d,e)=n3+1。
总结一:如果d的小数部分是e小数部分的前缀,则g(d,e)=h(d,e);否则g(d,e)=h(d,e)+1。
性质五:令某个桶的小数部分是v,0≤i<j<k<v.size()0\le i < j < k < v.size()0i<j<k<v.size()。h(i,j)表示v[i]和v[j]的最长公共前缀长度。
性质五一 h(i,j)≥h(i,k)\ge h(i,k)h(i,k)
推论一:如果v[i]和v[j]的公共前缀不是v[i],则v[i]和v[k]的公共前缀也不是v[i]。
性质五二:如果h(i,j)==h(i,k)==x,则∀jk,h(i,jk)=x,j≤jk≤k\forall jk,h(i,jk)=x,j \le jk \le kjk,h(i,jk)=x,jjkk
性质五三:h(i,k)≤\leh(j,k),故h(i-1,ij)≤\leh(i,ij)。→∀ij\rightarrow \forall ijij h(i-1,ij)都相等,因为,v[j∼k]的前x位都相等[j\sim k]的前x位都相等[jk]的前x位都相等。故可以永久删除k的信息。
性质六g(i−1,i)≥g(i,j)→g(i−1,j)==g(i,j)g(i-1,i) \ge g(i,j) \rightarrow g(i-1,j) ==g(i,j)g(i1,i)g(i,j)g(i1,j)==g(i,j) ;否则,g(i−1,j)=g(i,j)g(i-1,j)=g(i,j)g(i1,j)=g(i,j)

实现

Do2 处理a[i+1∼N−1]i+1 \sim N-1]i+1N1]

迭代前
sta的每个元素包括两个{x,cnt} 表示g(ai,aj)==xg(a_i,a_j)==xg(ai,aj)==x的数量,i<j<Ni < j < Ni<j<N。从栈底到栈顶,x升序。
迭代过程:
x1 = g(i-1,i)
cnt1=1
当栈顶x ≥\ge x1
{cnt1 += 栈顶cnt
出栈
}
{x1,cnt1}入栈

int sum = ∑(x+1)×cnt\sum (x+1) \times cnt(x+1)×cnt
∑j:iN−1g(ai,aj)=sum−栈顶cnt×(栈顶x==ai小数位数)\sum_{j:i}^{N-1}g(a_i,a_j)=sum - 栈顶cnt \times (栈顶x ==a_i小数位数)j:iN1g(ai,aj)=sum栈顶cnt×(栈顶x==ai小数位数)

Do 处理a[0∼i−10 \sim i-10i1]

和处理i∼N−1i \sim N-1iN1类似。
∑j:0N−1g(ai,aj)=∑j:0ig(ai,aj)+∑j:iN−1g(ai,aj)−ai小数的位数\sum_{j:0}^{N-1}g(a_i,a_j)=\sum_{j:0}^{i}g(a_i,a_j)+\sum_{j:i}^{N-1}g(a_i,a_j)-a_i小数的位数j:0N1g(ai,aj)=j:0ig(ai,aj)+j:iN1g(ai,aj)ai小数的位数
注意
由于d≤ed \le ede,故只有以下三种情况:
一,小数部分互为前缀,即两者相等。
二,d的小数部分是e小数部分的前缀,反之不成立。
三,互不为前缀。
以下不可能成立:
e的小数是d小数部分的前缀,反之不成立。和d≤ed\le ede矛盾。
性质七d的小数部分是否是e的小数部分的前缀⟺以下条件是否至少一个成立。一,d的小数部分是e小数部分的前缀。二,e的小数部分是d的小数部分的前缀d的小数部分是否是e的小数部分的前缀 \iff 以下条件是否至少一个成立。 一,d的小数部分是e小数部分的前缀。二,e的小数部分是d的小数部分的前缀d的小数部分是否是e的小数部分的前缀以下条件是否至少一个成立。一,d的小数部分是e小数部分的前缀。二,e的小数部分是d的小数部分的前缀
这样就不会重复扣除。在Do2中扣除g(0∼i−1,i)0 \sim i-1,i)0i1,i)。即如下代码:

					if (b){diff[i + 1]++;diff[i + 1 + cnt]--;}

大致过程

unorder_map<int,vector<pair<string,int>> mv

通过i枚举各数
mv[第i个数的整数部分].emplace_back(第i个数的小数部分,i)

for([tmp,v]:mv){
处理v
}

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include<array>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t);return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T = int>
vector<T> Read() {int n;cin >> n;vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}
template<class T = int>
vector<T> ReadNotNum() {vector<T> ret;T tmp;while (cin >> tmp) {ret.emplace_back(tmp);if ('\n' == cin.get()) { break; }}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;AuotToFile();}void writestr(const char* sz) {strcpy(m_p, sz);m_p += strlen(sz);AuotToFile();}inline void write(char ch){*m_p++ = ch;AuotToFile();}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);m_p = puffer;}~COutBuff() {ToFile();}
private:inline void AuotToFile() {if (m_p - puffer > N - 100) {ToFile();}}char  puffer[N], * m_p;
};template<int N = 1'000'000>
class CInBuff
{
public:inline CInBuff() {}inline CInBuff<N>& operator>>(char& ch) {FileToBuf();while (('\r' == *S) || ('\n' == *S) || (' ' == *S)) { S++; }//忽略空格和回车ch = *S++;return *this;}inline CInBuff<N>& operator>>(int& val) {FileToBuf();int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行		return *this;}inline CInBuff& operator>>(long long& val) {FileToBuf();long long x(0); int f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行return *this;}template<class T1, class T2>inline CInBuff& operator>>(pair<T1, T2>& val) {*this >> val.first >> val.second;return *this;}template<class T1, class T2, class T3>inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val);return *this;}template<class T1, class T2, class T3, class T4>inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);return *this;}template<class T = int>inline CInBuff& operator>>(vector<T>& val) {int n;*this >> n;val.resize(n);for (int i = 0; i < n; i++) {*this >> val[i];}return *this;}template<class T = int>vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {*this >> ret[i];}return ret;}template<class T = int>vector<T> Read() {vector<T> ret;*this >> ret;return ret;}
private:inline void FileToBuf() {const int canRead = m_iWritePos - (S - buffer);if (canRead >= 100) { return; }if (m_bFinish) { return; }for (int i = 0; i < canRead; i++){buffer[i] = S[i];//memcpy出错			}m_iWritePos = canRead;buffer[m_iWritePos] = 0;S = buffer;int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);if (readCnt <= 0) { m_bFinish = true; return; }m_iWritePos += readCnt;buffer[m_iWritePos] = 0;S = buffer;}int m_iWritePos = 0; bool m_bFinish = false;char buffer[N + 10], * S = buffer;
};struct CMyTrieNode
{array<CMyTrieNode*, 10> m_child;int m_iCnt = 0;//后代数量int m_iLeafeCnt = 0;//叶子节点数量
};
class CMyTrie {
public:void Add(const char* pStr, const char* pEnd) {auto p = &m_root;for (; pStr < pEnd; pStr++) {p->m_iCnt++;if (nullptr == p->m_child[*pStr - '0']) {p->m_child[*pStr - '0'] = new CMyTrieNode();}p = p->m_child[*pStr - '0'];}p->m_iCnt++;p->m_iLeafeCnt++;}CMyTrieNode m_root;
};class Solution {public:vector<long long> Ans(const int N, vector<string>& num) {unordered_map<int, vector<pair<string, int>>> mv;int inx = -1;for (const auto& s : num) {++inx;int pos = s.find('.');int i1 = atoi(s.c_str());					if (-1 == pos) {mv[i1].emplace_back("", inx);}else {mv[i1].emplace_back(s.substr(pos + 1), inx);}}vector<long long> ans(N);auto Do = [&](const vector<pair<string, int>>& v) {long long sum = 0;stack<pair<int, int>> sta;for (int i = 1; i < v.size();i++) {const string& s1 = v[i].first;const string& s2 = v[i - 1].first;int j = 0;for (; (j < s1.length()) && (j < s2.length()) && (s1[j] == s2[j]);j++);int cnt = 1;while (sta.size() && (j <= sta.top().first)) {cnt += sta.top().second;sum -= (sta.top().first + 1) * sta.top().second;sta.pop();}sta.emplace(j, cnt);sum += (j + 1) * cnt;	ans[v[i].second] += sum ;}};vector<int> diff;auto Do2 = [&](const vector<pair<string, int>>& v ) {long long sum = 0;diff.assign(v.size() + 1, 0);stack<pair<int, int>> sta;for (int i = v.size() - 2; i >= 0;i--) {const string& s1 = v[i].first;const string& s2 = v[i+1].first;int j = 0;for (; (j < s1.length()) && (j < s2.length()) && (s1[j] == s2[j]);j++);int cnt = 1;while (sta.size() && (j <= sta.top().first)) {cnt += sta.top().second;sum -= (sta.top().first + 1) * sta.top().second;sta.pop();}sta.emplace(j, cnt);sum += (j + 1) * cnt;const bool b = (j == v[i].first.length());ans[v[i].second] += sum - (b ? sta.top().second : 0);if (b){diff[i + 1]++;diff[i + 1 + cnt]--;}}int sum1 = 0;for (int i = 0;i < v.size();i++) {sum1 += diff[i];ans[v[i].second] -= sum1;}};inx = -1;for (auto& [tmp, v] : mv) {sort(v.begin(), v.end());	Do(v);	Do2(v);for (const auto& [s, inx] : v) {ans[inx] += s.length();}								}return ans;}};int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG	ios::sync_with_stdio(0); cin.tie(nullptr);//CInBuff<> in; COutBuff<10'000'000> ob;	int N;cin >> N;vector<string> num(N);for (int r = 0; r < N; r++) {cin >> num[r];}
#ifdef _DEBUG		//printf("N=%d", N);Out(num, ",num=");//Out(a, ",a=");//Out(ab, ",ab=");//Out(par, "par=");//Out(que, "que=");//Out(B, "B=");
#endif // DEBUG		auto res = Solution().Ans(num.size(), num);for (const auto& i : res) {cout << i << "\n";}return 0;
};

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

http://www.dtcms.com/a/486393.html

相关文章:

  • 设计一个个人网站手机app是用什么软件开发的
  • 盘锦做网站选哪家app网站开发后台处理
  • [AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第一篇:布置环境]
  • Spring Boot 3零基础教程,整合Redis,笔记12
  • 拆解数据法律定性三重进阶:从“财产”到“客体”再到“权益束”
  • 【Leetcodenowcode数据结构】单链表的应用(初阶)
  • ECEF坐标系中椭球简化为球的可行性与实践
  • 网站建设 中企高程企业邮箱
  • 逻辑回归实战:泰坦尼克号生存预测
  • 医疗网站建设哪个好用会员充值消费管理系统
  • 【Bug:docker】--Docker国内镜像源加载失败
  • 安阳做网站的公司网站建设开发软件教程
  • php做网站优点ui设计职业培训机构
  • 【ADS-1】【python基础-2】基本语法与数据结构(列表、字典、集合)
  • 简单的网站源码娱乐网站后缀是什么
  • C# 基于halcon的视觉工作流-章46-不匀面划痕
  • 一个手机的奇幻之旅(手机在基站间的切换)
  • Android thermal (4)_cooling device(上)
  • JavaEE初阶——TCP/IP协议栈:从原理到实战
  • 建设网站要买服务器徐闻网站建设公司
  • 我想网上做网站怎么做卖东西的网站
  • 用于汽车雷达应用的步进频率PMCW波形——论文阅读
  • 使用 python-docx 和 difflib 对比 Word 文档
  • 食品电子商务网站建设规划书开发网站的好处
  • 找人做的网站怎么运行精神堡垒设计
  • 开源 Linux 服务器与中间件(一)基本介绍
  • 开源 Linux 服务器与中间件(二)嵌入式Linux服务器和中间件
  • 公司建设一个网站有什么好处国外网站建设现状图分析
  • 绿色 网站 源码个人建网站怎么赚钱
  • 定时器的学习(二)