U V A 306 C i p h e r UVA306\ Cipher UVA306 Cipher
D
e
s
c
r
i
p
t
i
o
n
\mathcal{Description}
Description
Bob和Alice开始使用一种全新的编码方案。令人惊讶的是,这不是公共关键字密码系统,他们的编码和解码都是基于一种特殊的密码。他们于1996年2月16日在费城的最后一次会议上确定了他们的密码。他们把密码定为一个含有n个不同整数的数列,a1,…,an(0<ai<=n)。解码根据以下原则:把信息写在密钥的下方,使信息中的字符和密钥中的数字相应对齐。在位置i处的消息字符被写入位置ai处,其中ai是密钥中相应的编号。得到的消息以相同的方式继续被编码。重复这个过程k次,第k个编码即是最后答案。
消息的长度总是小于或等于n。若消息长度小于n,用空格补齐。
请你帮助Alice和Bob编写一个读取密钥的程序,进行k次编码,产生编码消息。
N < = 10 , 000 N<=10,000 N<=10,000
S
o
l
u
t
i
o
n
\mathcal{Solution}
Solution
最
初
想
法
最初想法
最初想法
求出整个置换的循环节长度, 对于后面的每个询问, 都模循环节后暴力进行模拟.
时间复杂度
O
(
循
环
节
大
小
∗
N
)
O(循环节大小*N)
O(循环节大小∗N),
L
u
o
g
u
Luogu
Luogu 上
A
C
\color{green}{AC}
AC,
V
J
u
d
g
e
V\ Judge
V Judge上
T
L
E
\color{blue}{TLE}
TLE.
正
解
部
分
正解部分
正解部分
由于 整个置换 的循环节大小为 所有 子循环节 大小的
L
C
M
LCM
LCM,
导致时间复杂度为
O
(
L
C
M
∗
N
)
O(LCM*N)
O(LCM∗N), 其中
L
C
M
LCM
LCM 的上限为
N
!
N!
N!, 在luogu竟然还能A.
但若求出每个位置单个的循环节, 对每个询问就可以 O ( s i z e ∗ N ) O(size*N) O(size∗N) 得到答案, s i z e size size 的上限为 N N N.
求出整个置换的循环节大小需要 2500 m s 2500ms 2500ms 左右,
但是求出单个循环节大小仅需要 20 m s 20ms 20ms.
实
现
部
分
实现部分
实现部分
没什么好说的.
C
o
d
e
\mathcal{Code}
Code
#include<cstdio>
#include<cstring>
#define reg register
const int maxn = 205;
int N;
int K;
int A[maxn];
int B[maxn];
int l[maxn];
char S[maxn];
char Ans[maxn];
void Work(){
getchar();
scanf("%[^\n]", S+1);
int len = strlen(S+1);
while(len < N) S[++ len] = ' ';
for(reg int i = 1; i <= N; i ++) B[i] = i;
for(reg int i = 1; i <= N; i ++){
int tmp = K % l[i];
while(tmp --) B[i] = A[B[i]];
}
for(reg int i = 1; i <= N; i ++) Ans[B[i]] = S[i];
for(reg int i = 1; i <= N; i ++) printf("%c", Ans[i]);
printf("\n");
}
int main(){
while(~scanf("%d", &N) && N){
for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]);
for(reg int i = 1; i<= N; i ++){
int t = i, to = A[i]; l[i] = 1;
while(to != t) l[i] ++, to = A[to];
}
while(~scanf("%d", &K) && K) Work();
printf("\n");
}
return 0;
}