poj1026--Cipher(置换群)

题目链接:点击打开链接

题目大意:给出一个编码的顺序,每经过一次编码第i位上的字符回到第a[i]位上。然后给出一个k,和初始的串,问编码k次后的串是什么。

k可能会很大,不能暴力,所以要用置换群,找出轮换的环,假设环中有m个数,那么每编码m次,就代表这又回到了初始状态,可以用k%m,这样减少编码的次数。如果在记录轮换的位置,那么对于轮换中的第i个字符编码k次,就变成了轮换中的第(i+k)%m个字符。这样直接可以计算出最终的结果。

注意,题目不难,但是输入让人头疼,,,,经过多次wa,测试出只有(getline除外):

gets(str) ;

int len = strlen(str) ;

for(i = len ; i <= n ; i++)

str[i] = ' ' ;

而且一定要有后面的for,不然就错误,,,,,


#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std ;
char str[210] , s[210] , ch ;
int cnt ;
int a[210] , vis[210] ;
vector <int> vec[210] ;
int vec_num ;
void grop(int n) {
    int i , j ;
    vec_num = 0 ;
    memset(vis,0,sizeof(vis)) ;
    for(i = 1 ; i <= n ; i++) {
        if( vis[ a[i] ] ) continue ;
        j = i ;
        while( !vis[ a[j] ] ) {
            vis[ a[j] ] = 1 ;
            vec[ vec_num ].push_back( j ) ;
            j = a[j] ;
        }
        vec_num++ ;
    }
}
int main() {
    int n , m , k , i , j , l , num , mod , temp ;
    while( scanf("%d", &n) && n ) {
        for(i = 1 ; i <= n ; i++) {
            scanf("%d", &a[i]) ;
        }
        for(i = 0 ; i < n ; i++) vec[i].clear() ;
        grop(n) ;
        while( scanf("%d", &k) && k ) {
            cnt = 0 ;
            memset(s,0,sizeof(s)) ;
            memset(str,0,sizeof(str)) ;
            /*getchar() ;
            while( ch = getchar() ) {
                if( ch == '\n' ) break ;
                str[++cnt] = ch ;
            }*/
            gets(str) ;
            int len = strlen(str) ;
            for(i = len ; i <= n ; i++)
                str[i] = ' ' ;
            for(i = 0 ; i < vec_num ; i++) {
                num = vec[i].size() ;
                for(j = 0 ; j < num ; j++) {
                    l = (j+k)%num ;
                    s[ vec[i][l] ] = str[ vec[i][j] ] ;
                }
            }
            for(i = 1 ; i <= n ; i++) {
                printf("%c", s[i]) ;
            }
            printf("\n") ;
        }
        printf("\n") ;
    }
    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值