原题:CF922D Robot Vacuum Cleaner
简要题意
给定一些仅由 s
和 h
组成的字符串,可以任意改变这些串之间的相对位置,组合成一个长串,要使长串中子序列 sh
的数量尽可能多。
思路
贪心妙题。
首先考虑一个序列中的子序列 sh
的数量如何计算,对于每一个 h
考虑前面有多少个 s
,前缀和即可。
把对答案的贡献分成 2 类:
- 每个串内部的子序列
sh
。 - 由不同串中的字符组成的子序列
sh
。
显然,前者不会受到每个串的排列顺序影响,所以只需考虑后者。
对于相邻两个串考虑,发现交换只会影响仅分别由这两个串中的一个字符组成的 sh
子序列(因为不影响两个串前面和后面的 s
和 h
的前缀和),所以如果交换能使答案变大,进行交换显然更优,故只要对所有串排序,排序比较关键字时考虑两个串交换前后仅分别由这两个串中的一个字符组成的 sh
子序列数量,使较大的在前面。对于排完序的序列,再进行任何交换都会使答案变劣,故贪心策略正确。
Code
#include<bits/stdc++.h>
using namespace std;
const long long N=100010;
char ch[N];
long long n,ss,sh;
long long ans;
struct Node
{
long long s,h;
}str[N];
inline bool cmp(Node a,Node b){return a.s*b.h>b.s*a.h;}
int main()
{
scanf("%lld",&n);
for(long long i=1;i<=n;++i)
{
scanf("%s",ch+1);
long long len=strlen(ch+1),cnts=0;
for(long long j=1;j<=len;++j)
cnts+=(ch[j]=='s'),ans+=(ch[j]=='h')*cnts;
str[i].s=cnts,str[i].h=len-cnts;
}
sort(str+1,str+1+n,cmp);
long long sums=0;
for(long long i=1;i<=n;++i)
ans+=str[i].h*sums,sums+=str[i].s;
printf("%lld",ans);
return 0;
}