AcWing 157 & 158

两个题目分别是考察的树的最小表示(157)和字符串的最小表示(158)。

字符串的最小表示

对于一个字符串 S S S,有众多的循环同构串,所谓最小表示就是这些循环同构串中字典序最小的那个串。我们可以采用一个 O ( n ) O(n) O(n)的算法求解出长度为 n n n的字符串的最小表示。

int n = strlen(s);
int k = 0,j = 1,i = 0;
while (i < n && j < n && k < n) {
	if (s[(i + k) % n] == s[(j + k) % n]) k ++;
	else {
		s[(i + k) % len] > s[(j + k) % len] ? i = i + 1 + k : j = j + 1 + k;
		k = 0;
		if (i == j) i ++;	
	}
}
i = min(i, j);

最后得到的 i i i就是最小表示的起点位于原字符串中的第 i i i位。

树的最小表示

树本身没有顺序一说,但是我们可以考虑树的 D F S DFS DFS序。我们已知树的 D F S DFS DFS序其实就是在对树进行 D F S DFS DFS的过程中,每一个节点出入栈的顺序,这和 157 157 157的题目条件类似,给出了你一棵树不同的 D F S DFS DFS序,问这两种是不是表示的同一棵树。
我们如何求解树的最小表示呢?如果对每一个子树,我们都取子树的最小表示,然后对于所有的子树的最小表示按照字典序从小到大排列,最后把这些字符串拼接起来,就构成了树的最小表示串了。
所以我们的思路就是, D F S DFS DFS找子树,对于每一棵子树我们都取他的最小表示串,最后拼接起来就可以,同时为了优化边界,我们假设这棵树初始是从个节点的子树,然后最后再返回这个节点即可。

157题解:

#include <bits/stdc++.h>

#define ill __int128
#define ll long long
#define PII pair <ll,ll>
#define ull unsigned long long
#define me(a,b) memset (a,b,sizeof(a))
#define rep(i,a,b) for (int i = a;i <= b;i ++)
#define req(i,a,b) for (int i = a;i >= b;i --)
#define ios std :: ios :: sync_with_stdio(false)

const double Exp = 1e-9;
const int INF = 0x3f3f3f3f;
const int inf = -0x3f3f3f3f;
const ll mode = 1000000007;
const double pi = 3.141592653589793;

using namespace std;

int n;
string s1, s2;

string dfs(string &str, int &u)
{
    u ++;  //跳过了每一个子树的进入
    vector<string > now;  //每一层的一个最小表示,其实就是以每一个节点为根节点看他的所有子树的最小表示
    while (str[u] == '0') now.push_back(dfs(str, u));
    u ++; //又跳过了最后的回溯

    sort(now.begin(),now.end());
    string ans = "0";  //这里要补上
    for (auto i : now) ans = ans + i;
    ans = ans + '1';
    return ans;
}

int main()
{
    ios;
    cin >> n;
    while ( n -- ) {
        cin >> s1 >> s2;
        s1 = '0' + s1 + '1';
        s2 = '0' + s2 + '1';
        int p1 = 0, p2 = 0;
        if (dfs(s1, p1) == dfs(s2, p2)) cout << "same" << endl;
        else cout << "different" << endl;
    }
    return 0;
}

158题解:水题

#include <bits/stdc++.h>

#define PII pair<int,int>
#define me(a, b) memset(a, sizeof(a), b)
#define ll long long
#define ull unsigned long long
#define ios std :: ios :: sync_with_stdio(false)

const int INF = 0x3f3f3f3f;
const int inf = -0x3f3f3f3f;
const double pi = acos(-1);
const int mode = 998244353;

using namespace std;

const int maxn = 1e6 + 10;
char s1[maxn], s2[maxn];
char now1[maxn], now2[maxn];

void get1(int len)
{
    int k = 0,i = 0,j = 1;
    while (k < len && i < len && j < len) {
        if (s1[(i + k) % len] == s1[(j + k) % len]) k ++;
        else {
            s1[(i + k) % len] > s1[(j + k) % len] ? i = i + 1 + k : j = j + 1 + k;
            k = 0;
            if (i == j) i ++;
        }
    }
    i = min(i, j);
    k = 0;
    for (;k < len;k++) now1[k] = s1[(i + k) % len];
    return ;
}

void get2(int len)
{
    int k = 0,i = 0,j = 1;
    while (k < len && i < len && j < len) {
        if (s2[(i + k) % len] == s2[(j + k) % len]) k ++;
        else {
            s2[(i + k) % len] > s2[(j + k) % len] ? i = i + 1 + k : j = j + 1 + k;
            k = 0;
            if (i == j) i ++;
        }
    }
    i = min(i, j);
    k = 0;
    for (; k < len;k ++) now2[k] = s2[(i + k) % len];
    return ; 
} 

int main()
{
    scanf ("%s%s",s1, s2);
    // cout << s1 << ' ' << s2 << endl;
    int len1 = strlen(s1),len2 = strlen(s2);
    get1(len1);
    get2(len2);
    bool flag = 1;
    for (int i = 0;i < len1;i ++) {
        if (now1[i] != now2[i]) {
            flag = 0;
            break;
        }
    }
    if (flag) {
        printf ("Yes\n");
        printf ("%s\n",now1);
    }
    else printf ("No\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CUCKyrie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值