【2020.12.02提高组模拟】球员(player) 题解

题意描述

基本的递推

①所有运动员姓氏的长度必须不同。

②每个运动员的姓氏必须是长度比其长的所有其他运动员姓氏的连续子串

潜在的球员分成 N
类,第i类的球员的姓氏恰好有i个字母,且每一类恰好有K个球员。 有多少种不同的方法选出满足要求的N个球员。答案对109+7取余。

Solution

看上去是字符串匹配,其实长度只差1,只用把更长的字符串砍掉最前面一个或者最后面一个然后直接比较是否相同即可,如果它长度是len-1的前缀和后缀相同,只要递推一次,注意map是不可重的,最后累加答案的时候不能加几次

substr是切割函数,s.substr(x,y)是从一个string里切除从x到y的字符串,若y==s.size()可省略

string输入用scanf两行泪

#include<bits/stdc++.h>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define ll long long
#define re register
#define inf 0x3f3f3f3f
using namespace std;
int  mod=1000000007;
const int N=53;
int n,k;
string s[N][1503],t1,t2;
int i,j,kk;
ll ans;
map<string,ll> m;
template <class T> inline void read(T &x){
	x=0;int g=1; char s=getchar();
	for (;s>'9'||s<'0';s=getchar())	if (s=='-') g=-1;
	for (;s<='9'&&s>='0';s=getchar()) x=(x<<1)+(x<<3)+(s^48);
	x*=g;
}
signed main()
{
	freopen("player.in","r",stdin);freopen("player.out","w",stdout);
	read(n);read(k);
	for (i=1;i<=n;i++)
		for (j=1;j<=k;j++)
			cin>>s[i][j];	
	for (i=1;i<=k;i++) m[s[1][i]]++;
	for (i=2;i<=n;i++)
	{
		for (j=1;j<=k;j++)
		{
			t1=s[i][j].substr(0,s[i][j].size()-1);
			t2=s[i][j].substr(1);
			if (m.find(t1)!=m.end())
			m[s[i][j]]=(m[t1]+m[s[i][j]])%mod;
			if (m.find(t2)!=m.end())
			if (t1!=t2)
			m[s[i][j]]=(m[t2]+m[s[i][j]])%mod;
		}
	}
	for (i=1;i<=k;i++) ans=(ans+m[s[n][i]])%mod,m[s[n][i]]=0;
	printf("%lld",ans);
	return 0;
}               

详见hash大犇的博客

原文地址:https://www.cnblogs.com/Ritalc/p/14075095.html