一道很简单的数学题。。。
题目简化:给定一个字符串,通过交换顺序使它不是一个回文串。
看上去很简单,用一个大模拟就行了。
数据: 3 ≤ n ≤ 2000 3\le n\le 2000 3≤n≤2000。
如果直接用模拟的话,时间复杂度就是 O ( n ! ) O(n!) O(n!),最坏情况下是 2000 ! 2000! 2000!。
注意看题目中的这几个字:交换顺序。这说明了这个字符串中的字符是不会改变的,而题目要求我们求有多少种情况使得这个字符串不是回文串。
与回文串相关,立马想到回文串的对称性!
所以第一步一定是先统计每个字符出现了多少次(这里建议用 map)。
for(int i=1;i<=n;i++)
{
cin>>c[i];
mp[c[i]]++;//用mp来统计个数
}
因为回文串具有对称性,所以我们只需要考虑一边,另一边跟这边也就一样了。
直接求非回文串的个数太麻烦,这里用了正难则反的思路:我们只需要求出有多少个回文串,再用总的个数减掉就是答案了。
总的个数很好求,就是 n ! n! n!,那回文串的个数怎么求呢?
我们前面说过,考虑回文串只需要考虑一边就行了,所以说我们只需要将每种字符出现的次数 mp[c[i]]除以 2 2 2 就可以了。由此,我们需要将 mp[c[i]]分成两类。
当 mp[c[i]]为偶数时
此时 mp[c[i]]可以直接被分成两部分,总的 n n n 也一定是偶数。一边就有 n 2 \frac{n}{2} 2n 个字母,每个字母之间互相交换,一共有 n 2 ! \frac{n}{2}! 2n! 种情况。
现在我们又对于每个字母进行讨论。
因为字母之间是可以两两交换的,总的方案也就有 m p c i ! mp_{c_{i}}! mpci! 种但是同一边交换是没有用的啊,所以我们还要再这个基础上再去掉重复的,也就是同一边的搭配情况,算下来是 ( m p c i / 2 ) ! (mp_{c_{i}}/2)! (mpci/2)!。
把上面的公式合在一起,我们就得到了一个字母的排列情况,即。
m p c i ! ( m p c i ) / 2 \frac{mp_{c_{i}}!}{(mp_{c_{i}})/2} (mpci

最低0.47元/天 解锁文章
627

被折叠的 条评论
为什么被折叠?



