The solution of「P14405 [JOISC 2015] 复制粘贴」
\(\textup{P14405 [JOISC 2015] 复制粘贴 2}\)
\(\textup{Link}\) | 洛谷文章 | \(\textup{Tag: }\)模拟,不明白为啥标签是动规。
模拟赛 T1。
\(\textup{Description}\)
给定字符串和操作,每个操作会复制一段串中文本并插入到给定的位置。
要求输出前 \(K\) 个操作过后的字符。
\(\textup{Solution}\)
暴力对正解几乎没有贡献,所以不赘述了。
$\textup{10 pts.}$
int K, M, N, l, r, x;
string s;
void slove(){
cin >> K >> M >> s >> N;
for( int i = 1; i <= N; i ++ ){
cin >> l >> r >> x;
string k, t;
for( int i = l; i < min( M, r ); i ++ ){
k += s[i];
}
for( int i = 0; i < min( M, x ); i ++ ){
t += s[i];
}
t += k;
for( int i = x; i < min( M, (int)s.size() ); i ++ ){
t += s[i];
}
s = t;
}
for( int i = 0; i < K; i ++ ) cout << s[i];
}
考虑到 \(K \le 200\) 非常突兀,于是从这里入手。
最后我们只需要知道前面 \(K\) 个,于是我们逐个去寻找它们的来时路。
自然而然可以想到实现,我们对于每个位置 \(p \le K\),反着从每一个操作,逆推上一次来的位置。
假设当前在第 \(i\) 个操作,考虑对于每个区间的影响:
- 新的 \([0,x_i) \gets\) (来自于)原来的 \([0,x_i)\);
- \([x_i,x_i + r_i - l_i) \gets [l_i, r_i)\);
- \([x_i + r_i - l_i,\cdots) \gets [x_i,\cdots)\);
这个是顺推的操作,我们把它逆过来就得到了:
- \(p < x_i\):不变;
- \(x_i \le p < x_i + r_i - l_i : \ p \gets l_i + ( p - x_i)\);
- \(p \ge x_i + r_i - l_i : \ p \to p -( r_i - l_i)\)。
按照意思模拟就行啦,复杂度 \(O(NK)\)。
\(\textup{Code}\)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 2e5 + 10;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 7;
int K, M, N, l[MAXN], r[MAXN], x[MAXN];
string s;
void slove(){
cin >> K >> M >> s >> N;
for( int i = 1; i <= N; i ++ ){
cin >> l[i] >> r[i] >> x[i];
}
for( int j = 0; j < K; j ++ ){
int p = j;//在当前这一步之后在串里面的下标
for( int i = N; i >= 1; i -- ){//反过来一遍一遍推
int len = r[i] - l[i];
if( p >= x[i] )
p = ( p < x[i] + len ) ? l[i] + ( p- x[i] ) : p - len;
}
cout << s[p];
}
}
signed main(){
ios::sync_with_stdio( 0 );
cin.tie( 0 ), cout.tie( 0 );
// freopen( "copy.in", "r", stdin );
// freopen( "copy.out", "w", stdout );
int T = 1;
// cin >> T;
while( T -- )
slove();
return 0;
}
\(\textup{Last}\)
如果您有所疑惑或我有所错漏,请您在评论区指出或找我,我会一定解答并且修改本题解。
如果您觉得本文写的还不错,那可以留个赞吗?
谢谢你看到这里~

浙公网安备 33010602011771号