ARC#058F Iroha Loves Strings(贪心+字符串处理+dp预处理)

15 篇文章 0 订阅
4 篇文章 0 订阅

题面在这里
这题网上找不到题解啊。。于是我就自己对着某大佬的ac代码看了inf小时后终于(假装)懂了。。

题意

小C有 N N 个字符串s1,s2,s3,...,sN,并且他准备选择一些字符串顺次连接起来。问所有能得到的字符串中长度为 K K 的字典序最小的。N2000,K104
可以得到 s1s3 s 1 s 3 ,不能得到 s3s1 s 3 s 1

做法

一个贪心的思想:
每次保存一个长度最长的串,并且字典序最小。这个字典序的比较不包括长度。也就是说,如果有两个串存在真包含关系,就要取长度较大的那个串。
每次加进来一个串s,都在原先的串中取一个前缀,将s拼接上去。在所有可能的拼接方式中选取最优的。
但是有一个限制是长度需要为 k k ,所以一个想法就是先dp预处理出i~n串中能拼出的长度,每次只取合法的方案,这样就能保证最终拼出的一定是长为k的。
另外比较字典序的时候,需要求两个串的lcp长度,然后比较lcp+1位的地方的大小。故需要用到exkmp。
具体见代码注释~感觉这题有些地方需要自己理解感受下。。

代码

/*
*   预处理;
*   贪心思想;
*   字符串字典序比较转化为求lcp;
*   各种细节;
*/
#include<bits/stdc++.h>
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)
#define N 2005
#define M 10005
#define ll long long
using namespace std;
int n, m, len, tp, tot, a[N], q[M], f[M<<1];
char s[N][M], s1[M<<1], ch[M];
bool fl[N][M], ok[M], vis[M];
struct node {
    int x, y; node() {}//x,y表示,将ch中的长为x的串和a[i]拼起来
    node(int a, int b) { x = a, y = b; }
} b[M];
inline void exkmp(char s[], int n) {
    int k = 1; memset(f, 0, sizeof f); f[1] = n;//这里必须清零,或者写成f[1] = 0;
    rep(i, 2, n) {
        f[i] = max(0, min(k+f[k]-i, f[i-k+1]));
        while(i+f[i] <= n && s[f[i]+i] == s[f[i]+1]) f[i]++;
        if(k == 1 || f[i]+i > f[k]+k) k = i;
    }
}
inline int cmp(const node &u, const node &v) {//比较函数,-1/0/1表示</=/>,等于相当于存在真包含关系
    if(!u.y && !v.y) return 0;
    if(!u.y) return -cmp(v, u);
    if(!v.y) {
        if(v.x < u.x) return 0;
        int t = f[u.x+u.y+1];
        if(u.x+t >= v.x) return 0;
        return s1[t+1] < s1[u.x+u.y+t+1] ? -1 : 1;
    }
    if(u.x == v.x) return 0;
    if(u.x > v.x) return -cmp(v, u);
    int t = f[u.x+u.y+1];
    if(u.x+t <= v.x) return s1[t+1] < s1[u.x+u.y+t+1] ? -1 : 1;
    t = f[v.x-u.x+1];
    if(v.x+t >= u.x) return 0;
    return s1[v.x-u.x+t+1] < s1[t+1] ? -1 : 1;
}
bool operator < (const node &x, const node &y) { return cmp(x, y) < 0; }
bool operator == (const node &x, const node &y) { return !cmp(x, y); }
int main() {
    scanf("%d%d", &n, &m);//a[i]是第i个串的长度
    rep(i, 1, n) { scanf("%s", s[i]+1); a[i] = strlen(s[i]+1); }
    fl[n+1][0] = 1;//fl[i][j]表示i到n的串中是否能拼出长度为j的串
    per(i, n, 1) rep(j, 0, m) {
        fl[i][j] = fl[i+1][j];//不选第i个串
        if(j >= a[i]) fl[i][j] |= fl[i+1][j-a[i]];//选第i个串
    }
    //ch保存目前为止【不考虑长度的字典序最小】且【最长】的串,并且之后是能拼出长度m的串的
    //ok[i]=1表示这是一个断点,len保存长度
    len = 0; ok[0] = 1;
    rep(i, 1, n) {
        if(!len) {
            if(fl[i+1][m-a[i]]) rep(j, 1, a[i]) ch[++len] = s[i][j];
            ok[len] = 1; continue;
        }
        //将当前串s[i]和目前最优串ch拼起来,exkmp预处理出任意一个后缀与该串的lcp,用f保存
        tot = 0;
        rep(j, 1, a[i]) s1[++tot] = s[i][j];//s1保存拼接后的串
        rep(j, 1, len) s1[++tot] = ch[j];
        exkmp(s1, tot);
        memset(vis, 0, sizeof vis);
        rep(j, 0, m) if(fl[i+1][m-j]) {//枚举前i个串能拼成的合法长度
            if(ok[j]) { vis[j] = 1; b[j] = node(j, 0); }
            if(j >= a[i] && ok[j-a[i]]) {
                if(vis[j]) b[j] = min(b[j], node(j-a[i], a[i]));
                else { vis[j] = 1; b[j] = node(j-a[i], a[i]); }
            }
        }
        q[1] = 0; tp = 1;
        rep(j, 1, m) if(vis[j]) {
            while(tp > 1 && b[j] < b[q[tp]]) tp--;
            if(b[j] == b[q[tp]]) q[++tp] = j;
        }//这里的'=='表示是一个真包含关系,都要保存下来,记录断点
        len = q[tp];
        if(b[len].y) rep(j, 1, a[i]) ch[b[len].x+j] = s[i][j];
        ch[len+1] = 0;
        memset(ok, 0, sizeof ok);
        while(tp) ok[q[tp--]] = 1;
    }//由于每次操作都保证了之后的串能拼出长度为m的,所以最后的答案长一定为m
    printf("%s\n", ch+1);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
区块链系统性能测试流程主要包括功能测试、性能测试、可靠性测试和安全性测试。 功能测试是测试区块链平台是否按照设计要求正确运行,其中节点管理是功能测试的一个关键点。节点管理测试可以验证一个节点的正常运行是否代表整个系统正常运行。由于区块链是一个分布式的系统软件,测试过程需要融入分布式思想,而不是仅停留在中心化软件上。在场景模拟的过程中,需要验证软件、硬件以及区块链自身操作的各种组合,这被称为混沌测试。 性能测试是测试区块链平台在不同负载下的性能表现。一个常用的区块链性能测试框架是Caliper,它可以测试不同的区块链实现,如fabric、sawtooth和Iroha。通过性能测试,可以评估区块链系统在处理交易、执行智能合约等方面的性能指标。 可靠性测试是测试区块链平台在各种异常情况下的可靠性表现。例如,模拟网络中断、节点故障、数据损坏等情况,验证区块链系统是否能够正确处理异常并恢复正常运行。 安全性测试是测试区块链平台的安全性能。这包括验证区块链系统的身份验证、数据隐私、数据完整性和防止非法操作等方面的安全性。安全性测试可以通过模拟各种攻击场景,并对区块链平台的安全机制进行评估和验证。 综上所述,区块链系统性能测试流程包括功能测试、性能测试、可靠性测试和安全性测试,以确保区块链平台的功能正常、性能优越、可靠性高和安全性强。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [区块链测试(二):区块链测试](https://blog.csdn.net/qq_24792941/article/details/122541495)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [区块链性能测试工具caliper](https://blog.csdn.net/get_set/article/details/81055220)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值