https://codeforces.com/problemset/problem/922/D
题意翻译
有n个由s,h 组成的串 这些串可以按照任意顺序连接 最大化sh子序列(不用连续)的数量
思路:首先要想到的是多出来的sh是后面拼接上去的h*前面出现的s总数。所以比较容易想到s尽量放前面,h尽量放后面。
所以开始想法就是单纯把h多的扔后面,然后hack了自己。hack:hhhs, sshhhhh
姑且把这个题看作套路的一种类型。
不管怎么拼接,一个串中原有的sh是不变的,多出来的是后面的H*前面s总数。
所以假如有两个ssh 和hhhs,决定拼接先后顺序是串a的s数目*串b的h数目和串a的h数目*串b的s数目哪个大,就选择哪个。所以按照这个去排序。那么怎么说明多个也是这样的呢?
考虑三个时候的情况。
S1:s1,h1,sh1
S2:s2,h2,sh2;
S3:s3.h3,sh3
设s1*h1>=s2*h1>=sx*hx
那么这样去挑两种选择发现:
按照刚才说的顺序去选,结果为d1:s1*h2+(s1+s2)*h3==s1*h2+s1*h3+s2*h3;
不按照刚才的选,结果为d2:s1*h3+(s1+s3)*h2==s1*h3+s1*h2+s3*h2;
会发现d1-d2=s2*h3-s3*h2,那么想让结果更大选择s2*h3和s3*h2更大的那种方式去拼接。所以是正确的。
启发:在原有串中拼接找一个新的结构可以从两个开始考虑,然后尝试能否三个类推过去。如果没有想法,猜测两个的操作是否更优莽一波。从最特殊简单的情况去猜测多维,在一些构造和贪心的推导过程中是十分常用的思想方法。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
string str[maxn];
struct P{
LL s,h,sh;
}p[maxn];
bool cmp(P A,P B)
{
return A.s*B.h>B.s*A.h;
}
int main(void)
{
LL n;cin>>n;
for(LL i=1;i<=n;i++) cin>>str[i];
for(LL i=1;i<=n;i++){
LL ans=0;
for(LL j=0;j<str[i].size();j++)
{
if(str[i][j]=='s') p[i].s++;
else if(str[i][j]=='h') p[i].h++,p[i].sh+=p[i].s;
}
}
sort(p+1,p+1+n,cmp);
LL sum=0;LL ans=0;
for(LL i=1;i<=n;i++){
sum+=ans*p[i].h;
ans+=p[i].s;
sum+=p[i].sh;
}
cout<<sum<<endl;
return 0;
}