首页 > 其他分享 >【XSY3993】自动机(构造)

【XSY3993】自动机(构造)

时间:2022-10-31 07:34:42浏览次数:45  
标签:状态 排列 XSY3993 构造 leq 读入 delta 自动机

题面

自动机

题解

题意:让你构造一个不超过 \(n+1\) 个状态的自动机,使得 \(1\sim n\) 的 \(n!\) 个排列中只有 \(q\) 个被该自动机接受。


\(q=n!\) 可以先特判掉。

然后找到第 \(q+1\) 小的排列 \(p\),那么我们可以让这个自动机只接受比 \(p\) 小的排列。那么我们现在要构造的自动机就变成了一个判断字典序的自动机了。

容易想到一种 \(n+3\) 个状态的构造方法:

设 \(a_0,a_1,\cdots,a_n,w,l\),其中 \(w\) 称作 “胜利状态”,\(l\) 称作 “失败状态”,\(a_0\) 是起始状态。

接下来是如何设置转移:

  • 对于任意的 \(0\leq i< n\),我们考虑状态 \(a_i\) 的转移 \(\delta(a_i,j)\):
    • 若 \(1\leq j< p_{i+1}\),那么我们令 \(\delta(a_i,j)\gets w\)。
    • 若 \(j=p_{i+1}\),那么我们令 \(\delta(a_i,j)\gets a_{i+1}\)。
    • 若 \(p_{i+1}<j\leq n\),那么我们令 \(\delta(a_i,j)\gets l\)。
  • 对于 \(w\) 的转移,我们令所有的 \(\delta(w,j)\gets w\)(\(1\leq j\leq n\))。
  • 对于 \(l\) 的转移,我们也令所有的 \(\delta(l,j)\gets l\)(\(1\leq j\leq n\))。
  • 对于 \(a_n\) 的转移,你想怎么连就怎么连,因为你发现自动机读入任意一个 \(1\sim n\) 的排列都不会经过 \(a_n\) 的转移。

然后我们只设置 \(w\) 为接受状态。

容易发现按这个自动机就是模拟了我们一位一位比较字典序的过程。如果读入的排列 \(p'<p\),最后则会结束在胜利状态 \(w\);如果 \(p'=p\),则会结束在 \(a_n\);如果 \(p'>p\),则会结束在失败状态 \(l\)。

接下来考虑如何优化状态数。

首先发现 “区分 \(p'=p\) 还是 \(p'>p\)” 是在做无用功(因为它们都不被接受),而且 \(a_n\) 向外的转移时闲置着的,所以我们考虑将 \(l\) 与 \(a_n\) 合并。然后对于 \(a_n\) 的转移,我们令所有的 \(\delta(a_n,j)\gets a_n\)(\(1\leq j\leq n\))。这样,如果读入的排列 \(p'\geq p\),则会结束在 \(a_n\)。那么,如果读入的排列 \(p'\geq p\),最后则都会结束在 \(a_n\)。

那么状态数降到了 \(n+2\)。

再想了一会发现单从自动机的结构上好像没有什么可优化的了。

看回题面:自动机要读入的是 \(1\sim n\) 的一个排列。

那么,如果读入排列 \(p'\) 时,发现 \(p'\) 的前 \(n-1\) 位都和 \(p\) 相同,那么就可以判断 \(p'\) 和 \(p\) 是相同的了。

那么 \(a_{n-1}\) 向外转移时只会走到 \(a_n\),于是可以将 \(a_{n-1}\) 和 \(a_n\) 合并。

状态数成功降到 \(n+1\)。

构造题还是做少了……

代码如下:

#include<bits/stdc++.h>
 
#define N 15
 
using namespace std;
 
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
 
int n,q,a[N];
int fac[N];
bool vis[N];
 
int main()
{
    n=read(),q=read()+1;
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i;
    if(q>fac[n])
    {
        puts("1");
        for(int i=1;i<=n;i++)
            printf("1 ");
        puts("\n1");
        puts("1 1");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        int t=(q-1)/fac[n-i]+1;
        q-=(t-1)*fac[n-i];
        for(int j=1,tot=0;j<=n;j++)
        {
            if(vis[j]) continue;
            tot++;
            if(tot==t)
            {
                a[i]=j;
                vis[j]=1;
                break;
            }
        }
    }
    //失败n号,胜利n+1号 
    printf("%d\n",n+1);
    for(int i=1;i<n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(j<a[i]) printf("%d ",n+1);
            if(j==a[i]) printf("%d ",i+1);
            if(j>a[i]) printf("%d ",n);
        }
        puts("");
    }
    for(int i=1;i<=n;i++)
        printf("%d ",n);
    puts("");
    for(int i=1;i<=n;i++)
        printf("%d ",n+1);
    puts("\n1");
    printf("1 %d\n",n+1);
    return 0;
}
/*
2 1
*/
/*
3 2
*/

标签:状态,排列,XSY3993,构造,leq,读入,delta,自动机
From: https://www.cnblogs.com/ez-lcw/p/16842959.html

相关文章

  • 力扣 889. 根据前序和后序遍历构造二叉树
    889.根据前序和后序遍历构造二叉树给定两个整数数组,preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历,postorder 是同一棵树的......
  • 力扣 105. 从前序与中序遍历序列构造二叉树
    105.从前序与中序遍历序列构造二叉树给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树......
  • 【XSY3905】字符串题(lyndon串,构造)
    题面字符串题题解设所有长度不超过\(n\)的串的集合为\(S\)。考虑找到一种方法,能够对一个lyndon串\(A\),直接求出\(A\)的下一个lyndon串。方法如下:先将\(A......
  • 【XSY2912】reo(构造)
    考虑先找到一个原树的根。对于第一种限制,\(b\)不能作为根。对于第二种限制,\(a\)不能作为根。找到可以作为根的一个点\(rt\),显然由于限制互不矛盾肯定能找到。对于第......
  • 【XSY2499】字符串(AC自动机+树状数组)
    题面DescriptionUPD:本题字符集为全体小写字母InputOutputSampleInput51abc3abcabc0abc3aba1abababcSampleOutput22HINT题解这个“强制在......
  • P5826 【模板】子序列自动机
    题目链接P5826【模板】子序列自动机【模板】子序列自动机题目背景本题中,若\(x\)是\(y\)的子序列,则等价于存在一个单调递增序列\(z\),满足\(|z|=|x|\),\(z_{|x|}......
  • Demo51_关于构造器有参构造的使用
    //构造器:有参构造的使用packagecom.oop.demo2;publicclassperson_3_2{Stringname;intage;publicperson_3_2(){}publicperson_3_2(Stringna......
  • Demo51_关于构造器_偏复杂
    //关于构造器packagecom.oop.demo2;//空的类中有默认的方法,默认的构造器//一个类即使什么都不写,它也会存在一个方法(构造器)publicclassPerson_3{//1.使用new关键......
  • 3 栈帧 递归 类成员 静态字段 常量 静态函数 属性 构造函数 析构函数 this readonly
    好记性不如烂笔头目录好记性不如烂笔头栈帧递归=深入了解类==1类成员2成员修饰符的顺序3静态字段4从类的外部访问静态成员4.1静态成员的生存期5静态函数成员6其他......
  • 【CF1396E】Distance Matching(构造)
    题意:给一棵\(n\)个点的树,保证\(n\)为偶数,你需要将这\(n\)个点两两配对,使得每对点的距离和恰好为\(k\)。判断无解或输出方案。\(n\leq10^5,k\leqn^2\)。题解:首......