牛客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}\)
對於 \(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;
}