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);
    }
    
  • 相关阅读:
    c# WinForm 定时执行某个后台操作 如把B文件夹下的文件Copy到A文件夹下
    c# 创建指定大小的空字符填充的文本文件 在指定位置读写相关内容
    c# DirectShow 通过IAMVideoProcAmp的Set方法 来设置视频图像的Brightness 调整亮度
    [转]灰度图像的腐蚀算法和细化算法(C#代码)
    利用fleximage实现图片上传
    利用acts_as_ferret实现全文检索
    纯CSS无hacks的跨游览器多列布局
    IE私有CSS样式属性一览
    利用thinking sphinx实现全文检索
    搭建rails运行环境
  • 原文地址:https://www.cnblogs.com/ucprer/p/14475131.html
Copyright © 2011-2022 走看看