专栏文章

题解 CF2047B

CF2047B题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqvi2ku
此快照首次捕获于
2025/12/04 11:25
3 个月前
此快照最后确认于
2025/12/04 11:25
3 个月前
查看原文

题意:

一个非常短的小写字母串,可以进行一次下标间的赋值操作,问如何得到最少的不同排列个数。

思路:

没有想到其它题解那样特别精妙的方法(主要是不会证),发现 nn 极小,于是愉快地打一个暴力。
回顾一下多重集合的排列公式,设我们有 nn 个元素,第 ii 种元素出现了 kik_i 次,排列数如下:
n!ki!\dfrac{n!}{\prod k_i!}
直接枚举所有不同的赋值方法,开桶存字符串不同字符的个数,用上述公式计算,找到最小值即可。代码很丑且十分的暴力,但不用证明结论。
复杂度 O(n3+n2w)O(n^3+n^2w)ww 为桶大小。

程序如下:

CPP
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int T,a[30];
char str[15];
int factorial(int x){
	int ret=1;
	for(int i=2;i<=x;i++)ret*=i;
	return ret;
}
int main(){
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%d%s",&n,str+1);
		char ans[15];
		int mn=2e9;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				char tmp[15];
				for(int k=1;k<=n;k++)tmp[k]=str[k];
				tmp[j]=tmp[i];
				memset(a,0,sizeof(a));
				for(int k=1;k<=n;k++)a[tmp[k]-'a']++;
				int cur=factorial(n);
				for(int k=0;k<26;k++)cur/=factorial(a[k]);
				if(cur<mn){
					mn=cur;
					for(int k=1;k<=n;k++)ans[k]=tmp[k];
				}
			}
		}
		for(int i=1;i<=n;i++)printf("%c",ans[i]);
		puts("");
	}
	return 0;
}

THE END

评论

0 条评论,欢迎与作者交流。

正在加载评论...