zoukankan      html  css  js  c++  java
  • 2018 ICPC Asia Jakarta Regional Contest C. Smart Thief (欧拉路径+哈希)

    题意:

    给定m个数字(m<=9),要求用这些数字构造出一个最短的串,使得它有k不同的个长度为n的连续子串。

    思路:

    两个相邻的子串,前一个串的后n-1位就是后一个子串的前n-1位,因此想到可以将这个构造问题转化为图上的问题。

    图上的点表示一个子串的后n-1位,边表示在后面插入一个新的数字(1~m),每个点都有m条边指向它能转化成的其他状态。一个点加上一条出边就代表了一个长度为n的子串,显然只要在图上走一条不经过重复边的路径,长度为k,就能得到答案。观察这个图可以发现每个节点都有m个出度和m个入度,因此它必定具有欧拉回路,所以答案要求的最短的串长度就是n+k-1,因为其k个子串都是不相同的。

    显然可以用Hierholzer算法找欧拉路,但是图上的点可能有很多,如果dfs的过程中深度超过了k或者答案栈中的元素个数超过了k就可以直接跳出输出答案(答案栈中的序列一定构成一条不经过重复边的路径)。

    因为节点的值很大,采用哈希的方式来判断一个点边是否被访问过。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+5;
    const ll mod=1e9+7;
    ll seed=2333;
    ll base[maxn];
    int dig[15];
    int st1[maxn],st2[maxn],top1=0,top2=0;//top1:递归深度,top2:答案栈大小,st1:当前递归序列,st2:答案栈
    int n,m,k;
    map<ll,int>vis;
    void print1(){
        for(int i=1;i<=n-1;i++)printf("%d",dig[0]);
        for(int i=1;i<=k;i++)printf("%d",dig[st1[i]]);
    }
    void print2(){
        for(int i=1;i<=n-1;i++)printf("%d",dig[0]);
        for(int i=1;i<=k;i++)printf("%d",dig[st2[top2--]]);
    }
    void dfs(ll x){//x:当前节点(数的后n-1位)
        if(top1>=k){//递归深度到k
            print1();exit(0);
        }
        for(int i=0;i<m;i++){//枚举边
            ll cur=(x*seed%mod+i)%mod;//当前数字
            if(!vis.count(cur)){
                vis[cur]=1;
                st1[++top1]=i;
                ll v;
                if(top1<n){//序列长度小于n
                    v=cur;
                }
                else{//序列长度达到n
                    v=cur-st1[top1-n+1]*base[n]%mod;
                    if(v<0)v+=mod;
                }
                dfs(v);
                top1--;//回溯
                st2[++top2]=i;
                if(top2>=k){//遍历到k个数字
                    print2();exit(0);
                }
            }
        }
    }
    int main () {
        base[1]=1;
        for(int i=2;i<=maxn-5;i++)base[i]=base[i-1]*seed%mod;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<m;i++)scanf("%d",&dig[i]);
        dfs(0);
    }
    
  • 相关阅读:
    python基础练习题(题目 矩阵对角线之和)
    python基础练习题(题目 对10个数进行排序)
    python基础练习题(题目 文本颜色设置)
    windows批处理执行图片爬取脚本
    Linux 设置网卡最大传输单位MTU
    Linux 查看开机 log
    Linux实现脚本开机自启动
    查看 linux flash 分区大小查看 linux flash 分区大小
    kernel 编译提示 mkimage command not found – U-Boot images will not be built
    linux内核编译中No rule to make ... ipt_ecn.c 的处理
  • 原文地址:https://www.cnblogs.com/ucprer/p/14475131.html
Copyright © 2011-2022 走看看