代码源:734、子串的循环移动

230 阅读2分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路 logo.png

题目描述

这是4月12日代码源div2的每日一题。

知识点:字符串

子串的循环挪动 - 题目 - Daimayuan Online Judge

给出一个字符串 s,你需要执行 m 个任务。每个任务给出两个下标 li,ri和一个整数 ki(字符串的下标从 1 开始),表示你需要循环挪动 s 的子串 s[li...ri] ki 次。请从前到后依次执行给出的每个任务。

字符串的循环挪动操作:将最后一个字符移到第一个字符的位置,并且将其他所有字符向右移一个位置。

比如:如果字符串 s 是 abacaba,一个任务为 l1=3,r1=6,k1=1,那么答案为 abbacaa。接下来一个任务为 l2=1,r2=4,k2=2,那么我们会得到 baabcaa

输入格式

第一行一个字符串 s,该字符串只包含小写英文字符。

第二行一个整数 m,表示任务个数。

接下来 m 行每行有三个整数 li,ri 和 ki。

输出格式

输出执行了 m 个任务后的最终的字符串 s。

样例输入

abacaba
2
3 6 1
1 4 2

样例输出

baabcaa

数据规模

对于所有数据保证,1≤|s|≤10000(|s| 表示字符串 s 的长度),1≤m≤300,1≤li≤ri≤|s|,1≤ki≤1000000

问题解析

每次进行移动,字符串会被分成三部分:s的头部,需要挪动的子串s2,s的尾部。然后我们知道,挪动k次,就相当于把长度为k的字符串从尾部挪去头部,所以我们也可以把需要挪动的子串分成两部分,长度为k的s2尾部子串(将要挪去前面的那部分),和将要从前面移动到后面的s2的头部子串,所以我们整体可以把字符串分成三部分:

s的头部s1,需要挪动的子串的头部s2,需要挪动的子串的尾部s3,s的尾部s4

此时s还是s1+s2+s3+s4。经过挪动后就变成了s1+s3+s2+s4(因为s3要挪到s2的前面)。那我们就分别获取这四段字符串,再拼接起来即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int MOD = 1e9 + 7, N = 1e6 + 10;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string str;
    cin >> str;
    int m,n=str.size();
    cin >> m;
    while (m--)
    {
        int l, r, k;
        cin >> l >> r >> k;
        int mod = (r - l + 1);
        string s1 = str.substr(0, l-1);
        string s2 = str.substr(l - 1, r - l - (k % mod) + 1);
        string s3 = str.substr(r-k%mod, k%mod);
        string s4 = str.substr(r, n - r + 1);
        if(l!=r)
            str = s1 + s3 + s2 + s4;
        
    }
    cout << str << endl;
    return 0;
}