洛谷1666 前缀单词

算法竞赛 动态规划
编辑文章

首先预处理一下两个单词 $s[i],s[j]$ 是否安全并记录在 $can[i][j]$ 中,用 $f[i]$ 代表包含第 $i$ 个单词的安全组有多少个。

枚举每一个小于当前单词的单词,如果他们俩安全,那么当前单词和 枚举单词所在的安全组成员 在一起也一定是安全的,所以加上答案即可。

$$f[j]= \begin{cases} f[j] \\ f[j]+f[i] , can[i][j] \& s[i]<=s[j] \end{cases}$$

所以很显然需要事先排序,还有虽然数据看起来小但答案其实很大,要开long long

string s[55];
bool can[55][55];
ll n,f[55],ans=1ll;

inline bool check(int x,int y)
{
    int len=min(s[y].length(),s[x].length());
    for (int i=0;i<len;i++)
    {
        if (s[x][i]==s[y][i]) continue;
        return 1;
    }
    return 0;
}

int main()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>s[i],f[i]=1;
    sort(s+1,s+n+1);
    for (int i=n;i;i--)
        for (int j=1;j<i;j++)
            can[i][j]=can[j][i]=check(i,j);
    for (int i=1;i<=n;i++)
        for (int j=i+1;j<=n;j++)
            f[j]+=can[i][j] ? f[i] : 0;
    for (int i=1;i<=n;i++) ans+=f[i];
    printf("%lld",ans);
    return 0;
}

新评论

称呼不能为空
邮箱格式不合法
网站格式不合法
内容不能为空