题目描述
小Hi有一个长度为N的字符串,这个字符串每个位置上的字符两两不同。现在小Hi可以进行一种剪切操作:
选择任意一段连续的K个字符,把这段子串剪下来,粘在串首或者串尾。例如ABCDE -> ADEBC、ABCDE -> BCADE或者ABCDE -> DEABC等。
小Hi想知道如果可以反复进行任意次剪切操作,他最多可能得到多少种不同的字符串。由于数目可能非常大,你只需要输出模P(P是质数)的余数即可。
框内内容来自某解说
字符串可以看作是对应元素间形成的一个置换群,连续子串的剪切操作即乘上另一个置换。
奇数长度对应的置换可以改变原置换逆序对数的奇偶性,而偶数长度的置换维持原有奇偶性不变。
故:
当
时,答案为
,
当
时,答案为原串生成的循环串数量,为
,
否则,
当
为奇数时,答案为
当
为偶数时,答案为
。
#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;
}