牛客IOI周赛23-普及组
比赛链接
牛客IOI周赛23-普及组
C.小L的编辑器
题目描述
小 L 发明了一个文本编辑器,由于小 L 非常垃圾,所以写出的文本编辑器也很垃圾。
该文本编辑器的运行方式大概是这样的:一开始文本为空,有一个光标在开头,每一次小 L 会输入一个字符,该字符就会被插入到光标的位置上,然后光标会随机地停留在该字符的左边或右边。
现在小 L 用这个文本编辑器打了一大段文字,但他却忘了保存了,他只记得他依次打了哪些字符和打完每个字符后光标停在了该字符的左边还是右边,你能帮助他还原出最终文本的内容吗?
输入描述:
输入文件有两行,第一行为一个字符串s,第二行为一个字符串t。
s, t 的长度相同,s 为一个仅包含小写字母的字符串,t 为一个仅包含'L', 'R' 的字符串。分别表示小 L 依次打了哪些字符,和每打完一个字符后光标停在了字符的左边还是右边( 'L' 为左边,'R' 为右边)。
输出描述:
输出仅一行一个字符串,为最终文本的内容。
示例1
输入
abcde
LLRLR
输出
cedba
说明
在每一时刻文本编辑器的状态如下("|"表示光标的位置):
|a
|ba
c|ba
c|dba
ce|dba
设 n 为 s, t 的长度。
对于 \(30 \%\) 的数据, 满足 \(n \leq 1000\) 。
另有 \(20 \%\) 的数据, 满足存在一个 \(\mathrm{x}\) 使得 \(0 \leq x<n, t_{0}=t_{1}=\ldots t_{x}=^{\prime} R^{\prime}, t_{x+1}=\ldots=t_{n-1}=^{\prime}\) \(L^{\prime}\) 。
对于 \(100 \%\) 的数据, 满足 \(1 \leq n \leq 1,000,000\) 。
解题思路
思维
当光标位于字符右边时,该字符总是在后面的字符的前面;当光标位于字符左边时,该字符总是在后面字符的后面,故只需按序输出为光标为 \(R\) 的字符,逆序输出光标为 \(L\) 的字符
- 时间复杂度:\(O(n)\)
代码
// Problem: 小L的编辑器
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/32762/C
// Memory Limit: 1048576 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int main()
{
string s,t;
cin>>s>>t;
int n=s.size();
s=' '+s,t=' '+t;
for(int i=1;i<=n;i++)
if(t[i]=='R')cout<<s[i];
for(int i=n;i>=1;i--)
if(t[i]=='L')cout<<s[i];
return 0;
}
D.小L的数列
题目描述
小L喜欢数和数列。小称 \(a_{1} \ldots a_{n}\) 这些数为优秀的。小称一个序列 \(b_{1} \ldots b_{m}\) 为好的当且仅当:
- 对于任意的 \(i(1 \leq i<m)\) ,满足 \(b_{i}<b_{i+1}\) 。
- 对于任意的 \(i(1 \leq i<m)\) ,满足 \(g c d\left(b_{i}, b_{i+1}\right)>1\) 。 其中, \(g c d(x, y)\) 为 \(x\) 和 \(y\) 的最大公因数,即最大的 \(d\) , 满足: \(d \mid x\) 且 \(d \mid y\) 。
- 对于任意的 \(i(1 \leq i \leq m) , b_{i}\) 这个数是优秀的。
现在,小想知道最长的能称为好的的序列的长度是多少,容易证明这个长度是有穷的。
输入描述:
有多组测试点, 输入第一行一个数 \(\mathrm{T}\) 表示测试点的个数。
对于每一个测试点有两行:
第一行一个正整数 \(n\), 表示优秀的数的个数
第二行 \(n\) 个整数 \(a_{1} \ldots a_{n}\), 表示小 L 称为优秀的数, 保证 \(a_{i}\) 两两不相同。
输出描述:
输出共 \(T\) 行, 每一行为一个测试点的答案, 即最长的好的序列的长度。
示例1
输入
2
5
4 6 3 2 9
9
10 2 5 3 6 9 7 8 1
输出
4
4
说明
对于第一个测试点来说,一个最长的好的序列可以是 [2, 4, 6, 9],长度为 4 。容易看出没有更长的好的序列。
对于第二个测试点来说,一个最长的好的序列可以是[3, 6, 8, 10],长度为 4 。容易看出没有更长的好的序列。
对于 \(30 \%\) 的数据, 满足 \(n, a_{i} \leq 10\) 。
对于 \(60 \%\) 的数据, 满足 \(n, a_{i} \leq 1000\) 。
另有 \(20 \%\) 的数据, 满足 \(n \leq 1000\) 。
对于 \(100 \%\) 的数据, 满足 \(2 \leq n \leq 100000,1 \leq a_{i} \leq 100000, T \leq 5, a_{i}\) 两两不同。
解题思路
分解质因数,dp
- 状态表示:\(f[i]\) 表示一个数的质因子为 \(i\) 的最长好序列长度
先将 \(a_i\) 排序,从头遍历 \(a_i\),对 \(a_i\) 分解质因数,找到最大的 \(f[i]\),并将所有的 \(f[j]\) (\(j\) 为 a_i$ 的质因数)更新为 \(f[i]\)
- 时间复杂度:\(O(t\times n\times max(\sqrt{a_i}))\)
代码
// Problem: 小L的数列
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/32762/D
// Memory Limit: 1048576 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=100005;
int t,n,a[N],f[N];
int main()
{
for(scanf("%d",&t);t;t--)
{
memset(f,0,sizeof f);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+1+n);
int res=0;
for(int i=1;i<=n;i++)
{
vector<int> b;
int t=0;
for(int j=2;j<=a[i]/j;j++)
{
if(a[i]%j==0)
{
while(a[i]%j==0)a[i]/=j;
f[j]++;
t=max(t,f[j]);
b.pb(j);
}
}
if(a[i]>1)f[a[i]]++,b.pb(a[i]),t=max(t,f[a[i]]);
res=max(res,t);
for(int k:b)f[k]=t;
}
printf("%d\n",res);
}
return 0;
}