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}\)

如果您有所疑惑或我有所错漏,请您在评论区指出或找我,我会一定解答并且修改本题解。

如果您觉得本文写的还不错,那可以留个赞吗?

谢谢你看到这里~

posted @ 2026-09-18 12:26  Fαll  阅读(2)  评论(0)    收藏  举报