【构造】构造一个字符串满足k个子序列问题总结

简介: 【构造】构造一个字符串满足k个子序列问题总结

题目 Codeforces Subsequences

题目链接 :Codeforces Subsequences

题目大意:
在这里插入图片描述

构造一个字符串,至少包含k个 codeforces子序列,并且字符串最短。

思路:构造

假设我们要找的不是 codeforces的子序列,而是 abcde。如果一个字符串中 a字母不在最前面,那么把它移到最前面其他不变的话,就多了一个 abcde序列。所以为了让序列更多,那么只需要将所有的 a都移动到最前面即可。 b跟着 a的后面, c跟着 b的后面,其他也如此。

每个字母的排序问题已经解决了,那么现在就是每个字母有多少个的问题了。答案是我们应该让每个字母的数量尽可能接近。

证明:子序列的数量就等于 SumA * SumB * SumC * SumD * SumESumA表示a的数量,如果 SumA - SumB > 1的话,那么(SumA - 1) * (SumB + 1) > SumA * SumB ,所以为了让字符串更短,所以让每个字母的数量尽可能接近。

现在我们就可以通过循环增加每个字符的数量,一旦乘积至少为k,那么就退出循环,最后打印每个字母的数量即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, inf = 0x3f3f3f3f, mod = 998244353;
int n, k;
ll a[N], c[N];
signed main()
{
#ifdef Xin
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif

    ll k;
    cin >> k;
    string s = "codeforces";
    int n = s.size();
    vector<int> a(n, 1);
    ll sum = 1;
    for (int i = 0; sum < k; i = (i + 1) % n)
    {
        sum = sum / a[i] * (a[i] + 1);
        a[i]++;
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < a[i]; j++)
            cout << s[i];
    }
    return 0;
}

小红的构造题

题目链接 :小红的构造题

题目大意:

在这里插入图片描述

构造一个字符串,至少包含k个 red子序列,并且字符串长度不超过200000

思路:构造

这道题就不能用上道题的方法了,为什么?

假设k == 1e14,那么为了让字符串最短,那么每个字目的长度为1e5,那么三个字母的长度就为3e5超过范围。为什么上道题可以那样写,因为codeforces有10个字母,每个字母长度假设有100,那么最多只需要1000个字符就能解决问题。

那这道题这么解决:

我们可以先构造这样一个字符串rererererere....,在第一个re后面加x个d,那序列个数就加了x个,如果在第二个re后面加了x个d,那么就增加了3*x子序列,依次类推,在第k个re后面加x个d,那就增加k*(k+1)*x/2个子序列。

所以为了让字符串长度越小,所以需要从后往前枚举,每次填入x个字符串即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, inf = 0x3f3f3f3f, mod = 998244353;
ll k;
ll a[N], c[N];
signed main()
{
#ifdef Xin
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif

    cin >> k;
    if (k == 0)
    {
        cout << "a";
        return 0;
    }
    int M = 80000;
    for (int i = 1; i <= M; i++)
    {
        a[i] = (ll)i * (i + 1) / 2;
    }
    int id = 0;
    for (int i = M; i >= 1; i--)
    {
        if (k >= a[i])
        {
            c[i] = k / a[i];
            k %= a[i];
        }
    }
    for (int i = 1; i <= M; i++)
    {
        cout << "re";
        while (c[i]--)
            cout << 'd';
    }

    return 0;
}
相关文章
|
5月前
|
存储 对象存储 C++
使用ostringstream处理字符串的方法详解
使用ostringstream处理字符串的方法详解
|
6月前
|
JavaScript 前端开发 API
|
5月前
|
人工智能 BI 索引
小红的字符串构造和小红的排列构造
小红的字符串构造和小红的排列构造
46 1
|
6月前
2020-10-10 数组和对象的区分方法
2020-10-10 数组和对象的区分方法
|
6月前
|
数据安全/隐私保护 C++
C++ 构造函数实战指南:默认构造、带参数构造、拷贝构造与移动构造
C++中的构造函数是特殊成员函数,用于对象初始化。类型包括默认构造函数(无参数)、带参数构造函数、拷贝构造函数和移动构造函数。默认构造函数设置对象默认状态,带参数构造函数允许传递初始化值。拷贝构造函数复制已有对象,移动构造函数高效转移资源。构造函数的访问权限可控制为public、private或protected。理解构造函数有助于编写健壮的C++代码。关注公众号`Let us Coding`获取更多内容。
87 0
|
6月前
|
存储 C++ 容器
Map容器-构造和赋值讲解
Map容器-构造和赋值讲解
52 0
|
6月前
通过c字符串对拷贝构造和赋值构造进行了解
通过c字符串对拷贝构造和赋值构造进行了解
47 0
|
存储 Java 对象存储
字符串相关的类
字符串相关的类
40 0
|
Java 编译器
重载的方法能否根据返回类型进行区分?
重载的方法不能根据返回类型进行区分。方法的重载是基于方法名称和参数列表来进行区分的,与返回类型无关。这是因为在Java中,编译器在确定要调用哪个重载方法时,仅根据传递给方法的参数来进行决策。
356 0
|
索引
字符串方法
字符串方法
101 0