您的位置:首页 > 博客中心 > 互联网 >

21.4.21 t1

时间:2022-05-11 12:42

tag:构造


题意

设计一个确定性有限状态自动机,使得恰好能接受1~n的全排列中的 \(q\) 个

\(n\leq12,0\leq q\leq n!\)

输出

第一行为状态数 \(Q(Q\le n+1)\)

接下来 \(Q\) 行,每行 \(n\) 个数。第 \(i\) 行第 \(j\) 个数 \(a_{i,j}\) 表示第 \(i\) 个状态在遇到 \(j\) 时会转移到状态 \(a_{i,j}\)

接下来一行一个数 \(q_0\) 表示初始状态为 \(q_0\)

接下来一行若干个数,第一个数为接受的状态数 \(n\),后面 \(n\) 个不同整数\(f_1,f_2\cdots f_n\) 表示接受状态 \(f_1,f_2\cdots f_n\)


实际上可以构造出自动机恰好接受从 \(1,2\cdots n\) 一直到第 \(q\) 个排列。

将第 \(n\) 个状态当作“垃圾桶”,第 \(n+1\) 个状态当作"终点"。这两个状态都是自己连自己。

举个例子就很明显了。\(n=4\),接受所有小于 \(3,2,4,1\) 的排列。

拆分一下:

  • 接受所有以 \((1)\)、\((2)\) 开头的排列

连 \((1\to n+1,1/2),\ (1\to2,3)\ (1\to n,4)\)

  • 接受所有以 \((3,1)\) 开头的排列

连 \((2\to n+1,1),\ (2\to3,2)\ (2\to,n,3/4)\)

  • 接受所有以 \((3,2,1)\)、\((3,2,4)\) 开头的排列

连 \((3\to n+1,1/4),\ (3\to n, 2/3)\)


思路就是逐位限定。当前状态向终点 \(n+1\) 的连边就是当前位接受的状态,然后再向下一个状态连一条边,其余的边都往垃圾桶 \(n\) 连。


#include
using namespace std;
 
template
inline void Read(T &n){
    char ch; bool flag=false;
    while(!isdigit(ch=getchar()))if(ch==‘-‘)flag=true;
    for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
    if(flag)n=-n;
}

int n, q;

char vis[15];
int ans[15][15];

int getnxt(int x){x++;while(vis[x])x++;return x;}

int main(){
    // freopen("1.out","w",stdout);
    Read(n); Read(q);
    int tp = 1;
    vis[0] = true;
    for(register int i=1; i

本类排行

今日推荐

热门手游