题目概要
对于给定的一个长度为 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;
}