解密运算
Time Limit: 10 Sec Memory Limit: 512 MB[Submit][Status][Discuss]
Description
对于一个长度为N的字符串,我们在字符串的末尾添加一个特殊的字符"."。之后将字符串视为一个环,从位置1,2,3,...,N+1为起点读出N+1个字符,就能得到N+1个字符串。
比如对于字符串“ABCAAA”,我们可以得到这N+1个串:
ABCAAA.
BCAAA.A
CAAA.AB
AAA.ABC
AA.ABCA
A.ABCAA
.ABCAAA
接着我们对得到的这N+1个串按字典序从小到大进行排序(注意特殊字符“.”的字典序小于任何其他的字符)结果如下:
.ABCAAA
A.ABCAA
AA.ABCA
AAA.ABC
ABCAAA.
BCAAA.A
CAAA.AB
最后,将排序好的N+1个串的最后一个字符取出,按照顺序排成一个新的字符串,也就是上面这个表的最后一列,就是加密后的密文“AAAC.AB”。
请通过加密后的密文求出加密前的字符串。
Input
第一行有两个整数N,M,分别表示加密前的字符串长度和字符集大小,其中字符用整数1,2,3,...,M编号,添加的特殊字符“."用0编号。
第二行为N+1个整数,表示加密后的字符串。
Output
输出仅一行,包含N个整数,用空格隔开,依次表示加密前字符串中每个字符的编号。
Sample Input
6 3
1 1 1 3 0 1 2
1 1 1 3 0 1 2
Sample Output
1 2 3 1 1 1
HINT
N,M<=200000
Solution
显然,按照权值(即这个字符串首字母)为第一关键字,位置(即这个字符后面的串的排名)为第二关键字排序。
然后这时候权值就是矩阵的第一列。
形如:
*ABCD
-----
-----
这时第一行后面ABCD的排名,显然就是读入中*的位置,因为*作为ABCD*的最后一个字符。
比如ABCD*排名为x,那么这时候 A 显然在矩阵第一列中的第x个,输出即可。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 #include<queue> 9 using namespace std; 10 typedef long long s64; 11 12 const int ONE = 2e6 + 5; 13 const s64 INF = 1e18; 14 15 int n, m; 16 struct power 17 { 18 int val, pos; 19 }a[ONE]; 20 21 int get() 22 { 23 int res=1,Q=1;char c; 24 while( (c=getchar())<48 || c>57 ) 25 if(c=='-')Q=-1; 26 res=c-48; 27 while( (c=getchar())>=48 && c<=57 ) 28 res=res*10+c-48; 29 return res*Q; 30 } 31 32 int cmp(const power &a, const power &b) 33 { 34 if(a.val != b.val) return a.val < b.val; 35 return a.pos < b.pos; 36 } 37 38 int main() 39 { 40 n = get(); m = get(); 41 for(int i = 1; i <= n + 1; i++) 42 a[i] = (power){get(), i}; 43 sort(a + 1, a + n + 1 + 1, cmp); 44 45 int pos = 1; 46 for(int i = 1; i <= n; i++) 47 { 48 pos = a[pos].pos; 49 printf("%d ", a[pos].val); 50 } 51 }