noi.ac#458 sequence

题目链接:戳我

蒟蒻的第一道子序列自动机!

给定两个01串A,B,求一个最短的01串,要求C不是A,B的子序列。要求如果同样短,输出字典序最小的。

那么我们先构建A,B两个串的子序列自动机。然后我们设\(f[i][j]\)表示现在已经匹配到A的第i位,B的第j位,现在还需要f[i][j]长度,才不是A,B的子序列。

那么\(f[i][j]\)从\(f[nxt_a[i][0/1]][nxt_b[i][0/1]]\)转移过来就行了。

比较重要的是如何构建出字典序最小的?
我们从x=0,y=0开始构建,每次选择ans-当前步数的状态,如果往后面接0合法,就优先接0,不行再接1.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 4010
#define INF 0x3f3f3f3f
using namespace std;
int lena,lenb,ans;
int cur[2],nxt_a[MAXN][2],nxt_b[MAXN][2],f[MAXN][MAXN];
char a[MAXN],b[MAXN];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%s",a+1),scanf("%s",b+1);
    lena=strlen(a+1),lenb=strlen(b+1);
    cur[0]=lena+1,cur[1]=lena+1;
    for(int i=lena;i>=0;i--)
    {
        nxt_a[i][0]=cur[0],nxt_a[i][1]=cur[1];
        if(i!=0) cur[a[i]-'0']=i;
    }
    cur[0]=lenb+1,cur[1]=lenb+1;
    for(int i=lenb;i>=0;i--)
    {
        nxt_b[i][0]=cur[0],nxt_b[i][1]=cur[1];
        if(i!=0) cur[b[i]-'0']=i;
    }
    f[lena+1][lenb+1]=0;
    nxt_a[lena+1][0]=lena+1,nxt_a[lena+1][1]=lena+1;
    nxt_b[lenb+1][0]=lenb+1,nxt_b[lenb+1][1]=lenb+1;
    for(int i=lena+1;i>=0;i--)
        for(int j=lenb+1;j>=0;j--)
        {
            if(i==lena+1&&j==lenb+1) continue;
            f[i][j]=INF;
            f[i][j]=min(f[i][j],f[nxt_a[i][0]][nxt_b[j][0]]+1);
            f[i][j]=min(f[i][j],f[nxt_a[i][1]][nxt_b[j][1]]+1);
        }
    ans=f[0][0];
    int x=0,y=0;
    for(int i=1;i<=ans;i++)
    {
        if(f[nxt_a[x][0]][nxt_b[y][0]]==ans-i)
        {
            printf("0");
            x=nxt_a[x][0],y=nxt_b[y][0];
            continue;
        }
        if(f[nxt_a[x][1]][nxt_b[y][1]]==ans-i)
        {
            printf("1");
            x=nxt_a[x][1],y=nxt_b[y][1];
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/fengxunling/p/11027120.html

时间: 2024-10-14 07:06:42

noi.ac#458 sequence的相关文章

SDOI2015 寻宝游戏 | noi.ac#460 tree

题目链接:戳我 可以知道,我们相当于是把有宝藏在的地方围了一个圈,求这个圈最小是多大. 显然按照dfs序来遍历是最小的. 那么我们就先来一遍dfs序列,并且预处理出来每个点到根的距离(这样我们就可用\(dis[u]+dis[v]-2*dis[lca(u,v)]\)来表示u,v之间的距离) 怎么动态维护这个东西呢?平衡树?不存在的,开一个set就行了.每次维护一下添加或者删除产生的影响就行了. 相似的题目是noi.ac#460 tree-- 给你一棵n个点的树,每个点都有一个颜色ci. 有m次操作

noi.ac #241 distance

话说这noi.ac是为了给蒟蒻增强信心还是干啥,这比赛后面几题搞的有点水啊.. 虽然第一题比较毒.. 这T3...水的一批... 直接先预处理一下每个点为根的到其他点的距离不就行了吗? 算了不说了... 直接给代码... #include <bits/stdc++.h> #define ll long long using namespace std; const ll N = 10010; ll head[N], Next[N<<1], ver[N<<1], edge

noi.ac #45 计数

\(des\) 给定 \(n\) 的全排列 + 一个值域属于 \([1, n]\) 的元素构成长度为 \(n + 1\) 的序列 问长度为 \(i\) 的本质不同的子序列的个数 \(sol\) 小学计数题 记 \(p + 1, q - 1\) 的元素相同 从起点到第一个相同元素长度 \(p\) 从终点到第二个相同元素长度 \(q\) 对于长度为 \(i\) 的本质不同的子序列的个数 可以用全部的答案 - 出现重复的个数 显然全部的答案 \(n + 1 \choose i\) 对于重复的答案,只存

noi.ac #46 最长上升子序列

\(des\) 长度为 \(n\) 的序列 \(A\),从中删去恰好 \(k\) 个元素(右边的元素往左边移动),记 \(cnt\) 为新 序列中 \(Ai = i\) 的元素个数(即权值与下标相同的元素的个数).求 \(cnt\) 的最大值. \(sol\) \(n ^ 2\) dp \(f_i\) 表示只保留 \(i\) 个的答案 转移 \(f_j = max(f_j, f_{j-1} + (x == j), j = min(i, m) -> 1\) 考虑 \(i\) 转移到 \(j\) 的

noi.ac #289. 电梯(单调队列)

题意 题目链接 Sol 傻叉的我以为给出的\(t\)是单调递增的,然后\(100\rightarrow0\) 首先可以按\(t\)排序,那么转移方程为 \(f[i] = min_{j=0}^{i-1}(max(t[i], f[j]) + 2 * max_{k=j+1}^i x[k])\) 不难发现,若\(i < j\)且\(x[i] < x[j]\),那么从\(i\)转移过来一定是不优的,一定是从\(i\)之前的某个位置转移过来.(f单增) 然后直接单调队列搞一搞就行了, #include&l

@noi.ac - [email&#160;protected] cleaner

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 小Q计划在自己的新家中购置一台圆形的扫地机器人.小Q的家中有一个宽度为 m 的走廊,走廊很长,如果将这个走廊的俯视图画在平面直角坐标系上的话,那么走廊的两堵墙可以分别看作直线 y=0 和直线 y=m,两堵墙之间的部分代表走廊. 小Q会按照顺序依次在走廊中安置 n 个家具.第 i 个家具

@noi.ac - [email&#160;protected] shuffle

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个长度为 n 的序列 s1,s2,-,sn,它有 2^n?1 个非空子序列.请对于每个 k=0,1,2,-,n 统计 s 有多少非空子序列 a 经过重排成 b 后,ai = bi 的位置数量的最小可能值恰好为k. input 第一行包含一个正整数 n ,表示序列的长度. 第二行包

@noi.ac - [email&#160;protected] game

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 小 Q 和小 T 正在玩一种双人游戏.m 张木牌从左往右排成一排,第 i 张木牌上写着一个正整数 bi.小 Q 和小 T 轮流行动总计 m 轮,小 Q 先手.在每一轮中,行动方需要选择最左或者最右的一张木牌并将其拿走.游戏最后每个人的得分即为他拿走的木牌上写着的数字之和,得分较大的一方

noi.ac #525 神树的权值

mcfx神仙的题qwq 题目链接:戳我 首先,我们知道30%的分还是挺好做的 直接枚举根,然后dfs一遍以\(O(n)\)的时间复杂度求出来有多少神仙点 代码如下: #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #define MAXN 100010 using namespace std; int n,t; in