题目概要
对于给定的一个长度为 n n n 的字符串,初始时,我们将它视作 n n n 个长度为 1 1 1 的字符串的可重集,然后重复下列操作 n − 1 n-1 n−1 次:
- 从这些字符串中任取两个字符串 s , t s,t s,t,将它们删除,将 s + t s+t s+t 加入集合。注意这里的 + + + 是指字符串拼接。
操作的成本被定义为 ∑ c ∈ { a , b , ⋯ , z } f ( s , c ) × f ( t , c ) \sum_{c\in\left\{\texttt{a},\texttt{b},\cdots,\texttt{z}\right\}}f\left(s,c\right)\times f\left(t,c\right) ∑c∈{a,b,⋯,z}f(s,c)×f(t,c),其中 f ( s , c ) f\left(s,c\right) f(s,c) 是字符 c c c 在 s s s 中出现的次数。更通俗地说,每次操作的成本为每个小写字母在两个字符串中出现次数的积。
现在给定一个非负整数 k ( 0 ⩽ k ⩽ 1 0 5 ) k\left(0\leqslant k\leqslant 10^5\right) k(0⩽k⩽105),请你构造一个不超过 1 0 5 10^5 105 个字符的可重集,使得操作成本的最小值为 k k k。可以证明,这样的解一定是存在的。
思路概述
我觉得话这一道题目就是一个简单的构造题目,随便取一段字符串来看看,就不难发现就是一个等差数列,所以说最小的合并应该就是按字典序排列以后的顺序合并。所以代码的结构差不多就是直接循环走一遍,然后如果可以输出就输出,不然就不输出。
然后我们证明一下:
考虑对于每一对
(
i
,
j
)
\left(i,j\right)
(i,j) 满足
s
i
=
s
j
s_i=s_j
si=sj 计算贡献,然后我们可以每次合并看一下,他到底想让我们干什么东西,所以不难得出:如果合并
s
,
t
s,t
s,t,本质就是计算有多少
(
x
,
y
)
\left(x,y\right)
(x,y) 满足
s
x
=
t
y
s_x=t_y
sx=ty。所以我们就可以等到两个东西合并后再计算答案。所以最后就跟上面的一样,就是贪心。
代码部分
#include<bits/stdc++.h>
using namespace std;
int k,f[10005];
char ans='a';
signed main()
{
cin>>k;
if(k==0)
cout<<ans;
int i=1;
for(i=1;f[i-1]<=k;i++)
f[i]=f[i-1]+i;
for(int j=i-1;j>=1;j--)
{
while(k>=f[j])
{
k-=f[j];
int t=j+1;
while(t--)
cout<<ans;
ans++;
}
}
return 0;
}