zoukankan      html  css  js  c++  java
  • 【洛谷5794】[THUSC2015] 解密运算(模拟)

    点此看题面

    大致题意: 对于一个字符串,我们在其末尾添加一个'.',将字符串视作一个环,则可以从(n+1)个位置断开得到(n+1)个新串。现将这(n+1)个新串按字典序排序('.'的字典序最小),按序给出排序后每个串末位字符,求原字符串。

    前言

    在一家咖啡店看到这题,在纸上乱涂乱画半天,最后口胡了出来。

    不过当时做法比较复杂,后来吃饭时想了想给它整理了一下,最后写出来的做法就很简洁了。

    手玩

    首先我们来手玩一下样例,或许能从中发现什么。

    样例给出的末位字符串是"AAAC.AB"。

    通过这个末尾字符串,其实题目还间接给了我们一个信息,即这个字符串显然是由".AAAABC"这七个字符构成的。

    而由于它是按字典序排列的,显然首位字符就应该按次是".AAAABC"。

    把它写成一个方阵形式,就是:

    [left{egin{matrix}.&?&?&?&?&?&A\A&?&?&?&?&?&A\A&?&?&?&?&?&A\A&?&?&?&?&?&C\A&?&?&?&?&?&.\B&?&?&?&?&?&A\C&?&?&?&?&?&Bend{matrix} ight} ]

    由于字符串成环,也就是说,在上面的每一个字符串中,首位字符在原字符串里都跟在末位字符后面。

    也就是说,'.'后面是'A','A'后面是'.'或'A'或'A'或'B','B'后面是'C','C'后面是'A'。

    再次因为这些字符串是按字典序排列的,所以我们可以把每种字符后面能够跟着的那些字符排个序,然后再依次填入方阵中。

    于是就得到了:

    [left{egin{matrix}.&A&?&?&?&?&A\A&.&?&?&?&?&A\A&A&?&?&?&?&A\A&A&?&?&?&?&C\A&B&?&?&?&?&.\B&C&?&?&?&?&A\C&A&?&?&?&?&Bend{matrix} ight} ]

    上面的做法似乎给了我们点启发,于是我们就可以套路地想到:

    "A."后面跟着的是'A',"AA"后面跟着的是'.'或'A',"CA"后面跟着的是'A',".A"后面跟着的是'B',"AB"后面跟着的是'C',"BC"后面跟着的是'A'。

    填入方格中,就得到:

    [left{egin{matrix}.&A&B&?&?&?&A\A&.&A&?&?&?&A\A&A&.&?&?&?&A\A&A&A&?&?&?&C\A&B&C&?&?&?&.\B&C&A&?&?&?&A\C&A&A&?&?&?&Bend{matrix} ight} ]

    按照这样的套路,我们就可以轻松把这个矩阵填完整了,剩下的请读者自己去尝试。

    而如果把这个算法用程序实现,就是(O(n^2))的复杂度,已经能够得到(60)分的好成绩了。

    优化

    接下来,我们该怎么优化呢?

    如果你认认真真把样例给手玩完了,你或许可以发现一个规律:对于每一个串,它总是从同一个串转移过来的。

    例如上面的第一个串,它的下一个字符总是从上面的第五个串得到的。

    这让我们想到,如果能够直接求出每个串的字符从哪个串转移过来,这道题似乎就做完了。

    而这其实是很好求的。

    具体地,首先我们把题目中给出的末位字符排序,就得到首位字符串。

    然后我们把每个字符串以末位字符为第一关键字、首位字符为第二关键字、编号为第三关键字再次排序,排序完后的第(i)个字符串的编号所对应的原先的字符串,就是向它转移的字符串。

    如果把转移看作一条边,我们只要从第一个字符串出发,沿反向边遍历一遍,每次取原先字符串(即题目中按字典序排序的字符串)的首位字符(不难发现,原先字符串的首位字符是以首位字符为关键字排序后的结果),就是答案。

    至于为什么这么做,有点难以描述,实在不清楚就自己去画画图吧,应该还是比较显然、好理解的。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 200000
    using namespace std;
    int n,m,a[N+5];struct data
    {
    	int H,T,p;I data(CI x=0,CI y=0,CI t=0):H(x),T(y),p(t){}
    	I bool operator < (Con data& o) Con {return T^o.T?T<o.T:(H^o.H?H<o.H:p<o.p);}
    }s[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    int main()
    {
    	RI i;for(F.read(n),F.read(m),i=1;i<=n+1;++i) F.read(a[i]),s[i].T=a[i],s[i].p=i;//读入
    	for(sort(a+1,a+n+2),i=1;i<=n+1;++i) s[i].H=a[i];sort(s+1,s+n+2);//排序求出首位字符,然后再次排序
    	i=s[1].p;W(i^1) F.write(a[i],' '),i=s[i].p;return F.clear(),0;//遍历,输出首位字符,注意第一个'.'无需输出
    }
    
  • 相关阅读:
    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5794.html
Copyright © 2011-2022 走看看