D. Robot Vacuum Cleaner(思维+贪心(经典))详解

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;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108625529