hihoCoder P1801 [编程练习赛72] 剪切字符串【字符串置换】

题目描述

小Hi有一个长度为N的字符串,这个字符串每个位置上的字符两两不同。现在小Hi可以进行一种剪切操作:
选择任意一段连续的K个字符,把这段子串剪下来,粘在串首或者串尾。例如ABCDE -> ADEBC、ABCDE -> BCADE或者ABCDE -> DEABC等。
小Hi想知道如果可以反复进行任意次剪切操作,他最多可能得到多少种不同的字符串。由于数目可能非常大,你只需要输出模P(P是质数)的余数即可。

框内内容来自某解说


字符串可以看作是对应元素间形成的一个置换群,连续子串的剪切操作即乘上另一个置换。
奇数长度对应的置换可以改变原置换逆序对数的奇偶性,而偶数长度的置换维持原有奇偶性不变。
故:
N = K 时,答案为 1
N = K + 1 时,答案为原串生成的循环串数量,为 N
否则,
K 为奇数时,答案为 N !
K 为偶数时,答案为 N ! 2


#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define For(I,X,Y) for(LL I=(X);I<=(Y);I++)
#define ForDown(I,X,Y) for(LL I=(X);I>=(Y);I--)
using namespace std;

inline LL Read(){
    LL X=0;char CH=getchar();bool F=0;
    while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
    while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
    return F?-X:X;
}

LL N,K,P,Ans=1ll;

int main(){
    N=Read(),K=Read(),P=Read();

    if(N==K) printf("1");
    else if(N==K+1) printf("%d",N%P);
    else {
        For(I,3,N) Ans=(Ans*I)%P;
        if(K&1) printf("%lld",(Ans<<1)%P);
        else printf("%lld",Ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/81808227