题解:P14118 [SCCPC 2021] Hotpot
题解:P14118 [SCCPC 2021] Hotpot
Part1:
刚入手此题,没仔细看数据范围,就信心满满的打了个暴力,从 \(1\) 循环到 \(m\),每次按照题目描述的进行操作,一个复杂度 \(O(Tm)\) 的暴力就打好了。最后,在 \(m\le10^9\) 的数据下,我毫不意外的 TLE了。
#include<bits/stdc++.h>
using namespace std;
int a[100010],b[100010],c[100010];
int main() {
int t;
cin>>t;
while(t--) {
int n,k,m;
cin>>n>>k>>m;
for(int i=0;i<n;i++) {
cin>>a[i];
b[i]=0;
}
for(int i=1;i<=k;i++) {
c[i]=0;
}
//暴力模拟操作。
for(int i=0;i<m;i++) {
if(c[a[i%n]]<1) {
c[a[i%n]]++;
}
else {
c[a[i%n]]--;
b[i%n]++;
}
//cout<<a[i%n]<<" "<<c[a[i%n]]<<" "<<i<<" "<<b[i]<<"\n";
}
for(int i=0;i<n;i++) {
cout<<b[i]<<" ";
}
cout<<"\n";
}
return 0;
}
Part2:
再重新分析题目后,我发现,在 \(m\) 次的操作里,每 \(2\times n\) 次就会发生循环,我抓住了这一点,将这一段代码:
for(int i=0;i<m;i++) {
if(c[a[i%n]]<1) {
c[a[i%n]]++;
}
else {
c[a[i%n]]--;
b[i%n]++;
}
}
拆分成了三段代码。
- 第一段:
for(int i=0;i<2*n;i++) {
if(c[a[i%n]]<1) {
c[a[i%n]]++;
}
else {
c[a[i%n]]--;
b[i%n]++;
}
}
将操作进行 \(2\times n\) 次,完成其中的一个循环。
- 第二段:
for(int i=0;i<n;i++) {
b[i]*=m/(2*n);
c[i]*=m/(2*n);
}
将每一个 \(b_i\) 和 \(c_i\) 都乘上总共的周期数。
- 第三段:
for(int i=0;i<m%(2*n);i++) {
if(c[a[i%n]]<1) {
c[a[i%n]]++;
}
else {
c[a[i%n]]--;
b[i%n]++;
}
}
将剩下的操作数补满,完成操作。
这样,我们成功的将 \(O(Tm)\) 优化成了 \(O(T2n)\),通过了这道题。
Part3:
最终代码:
#include<bits/stdc++.h>
using namespace std;
int a[100010],b[100010],c[100010];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--) {
int n,k,m;
cin>>n>>k>>m;
for(int i=0;i<n;i++) {
cin>>a[i];
b[i]=0;
}
for(int i=1;i<=k;i++) {
c[i]=0;
}
//将操作进行2*n次,完成其中的一个循环。
for(int i=0;i<2*n;i++) {
if(c[a[i%n]]<1) {
c[a[i%n]]++;
}
else {
c[a[i%n]]--;
b[i%n]++;
}
}
//将每一个b[i]和c[i]都乘上总共的周期数。
for(int i=0;i<n;i++) {
b[i]*=m/(2*n);
c[i]*=m/(2*n);
}
//将剩下的操作数补满,完成操作。
for(int i=0;i<m%(2*n);i++) {
if(c[a[i%n]]<1) {
c[a[i%n]]++;
}
else {
c[a[i%n]]--;
b[i%n]++;
}
}
for(int i=0;i<n;i++) {
cout<<b[i]<<" ";
}
cout<<"\n";
}
//完美结束!
return 0;
}

浙公网安备 33010602011771号