TC SRM599 div2 p950

本文介绍了一种解决TC题目中相似名称计数问题的方法。通过使用组合数公式和字典序排序来确定所有前缀连通块,再采用动态规划(DP)策略求解方案数量。具体步骤包括字符串排序、前缀匹配、状态转移矩阵构建等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tc的题意还是非常好理解的,所以也就不再赘述题意。

首先,对于这道题,我第一个想的就是组合数公式,首先对所有的字符串进行字典序排序,这样的话,所有的前缀连通块就全都凑到了一起,然后数出来所有的连通块的长度,按照组合数公式往里面套,就可以了,但是组合数取模还是忘了= =于是乎就没有按着这个方法写。

另一个方法貌似是dp,说实话,最开始并没有想到dp的这个姿势(果然还是dp太渣渣了)。

dp[i][j]表示的是以第i个字符串为结尾,前缀连续长度为j的方案数,当然我们目前只考虑这个前缀的规律,因为剩下的随意,直接乘以阶乘就可以啦~~那么这个数一定来自于以第i个字符串的所有的前缀为结尾,前缀连续长度为j-1个的时候的方案数,那么我们只需要预处理出来每一个字符串的前缀是第几个,就可以得到这个方法了。

代码如下

class SimilarNames2 {
public:
    typedef long long ll;
    ll a[55], dp[55][55];
    vector<int> adj[55];
    void init(){
        memset(a, 0, sizeof(a));
        a[0] = 1;
        for (int i = 1; i <= 50; i++)
            a[i] = (a[i - 1] * i) % mod;
    }
    bool judge(string a, string b){
        return b.find(a) == 0;
    }
	int count(vector <string> names, int L){
        init();
        int n = names.size();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (i == j) continue;
                else if (judge(names[i], names[j])) adj[j].push_back(i);
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; i++) dp[i][0] = 1;
        for (int j = 1; j < L; j++)
            for (int i = 0; i < n; i++)
                for (int k = 0; k < adj[i].size(); k++){
                    int x = adj[i][k];
                    dp[i][j] = (dp[i][j] + dp[x][j - 1]) % mod;
                }
        ll ans = 0;
        for (int i = 0; i < n; i++)
            ans = (ans + dp[i][L - 1] * a[n - L]) % mod;
        return (int)ans;
	}
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值