考虑一个字符集合(中元素互不相同)和一个长度为的字符串,其中中的字符都属于集合。
给你一个包含 个整数的序列 ()。你可以对字符串 作以下的操作:
1.选择一个合法的 ,并且令 ;
2.取出 中前 个字符 ;
3.取出 中后 个字符 ;
4.将 中前 个字符替换成翻转后的 ;
5.将 中后 个字符替换成翻转后的 ;
举个例子,我们令 "abcdefghi", 。这时 "ab", "hi",翻转后有 "ba", "ih",那么最终得到的字符串 就是 "ihcdefgba"。
这个操作可以被执行许多次(可能是零次),任何一个 也可以被使用多次。
我们将字符串 和 称为相等的字符串,当且仅当存在一个操作序列,将字符串 变成 。对于上面的例子来说,"abcdefghi" 和 "ihcdefgba" 是相等的。注意到 和它自己也是相等的。
你的任务很简单,数出互不相同的字符串的个数。
最终的答案可能会非常大,因此你只需要输出答案 的结果。
,,。
记字符集大小为 。
观察到一次操作相当于是把 的前 位和 的后 位按位交换,即
那么考虑把 “对折”,问题就变成了有两个长度为 的字符串 和 ,每次操作可以选一个 ,交换 和 ,问有多少种本质不同的 ( 和 拼起来的字符串)。特别的,如果 是奇数,那么中间那个位置永远不会被操作到,可以单独处理。
不难发现,由于操作中的 一定是序列 中的某个数,并且同一个 最多只会操作一次。所以我们关心的只是 是否等于 。因为若不等则交换后结果不一样,否则结果一样。为了表述方便,不妨记它们为 和 。
下面的部分瞟了一眼题解才会。
考虑枚举每一个 :
- 的情况:共有 种方案;
- 的情况:共有 种方案,除以 是因为交换后的也枚举过。
这两种情况的方案数加起来,再乘起来,最后永远不会被操作到的单独处理即可。
部分代码:
int ans=1;
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
int eq=qpow(v,b[i]-b[i-1]);
int neq=1ll*qpow(v,b[i]-b[i-1])*(qpow(v,b[i]-b[i-1])-1)%p*qpow(2,p-2)%p;
ans=1ll*ans*(eq+neq)%p;
}
ans=1ll*ans*qpow(v,n-b[m]-b[m])%p;