首页 > 试题广场 >

小猿的打字机

[编程题]小猿的打字机
  • 热度指数:72 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
小猿有一台打字机,只能打出‘A’、‘B’、‘C’三种字符。某天,小猿打了一段长度为N的字符串1,然后发现可以通过打字机的快捷操作来快速改写字符串。
已知一次快捷操作必须同时改写K个不同位置的字符,且被改写的字符必须改成打字机可以打出的其他字符。例如,K=2时,"AB"可以被改写为"CA",也可以被改写为"BC",但不可以被改写为"AA"(必须恰好改写K个字符)或"EF"。
可以请问通过M次快捷操作,能有多少种将字符串1改写为目标字符串2的方案?输出方案数对1000000007取模的结果。

输入描述:
第一行输入三个整数,N、M、K。
接下来两行输入原始字符串1和目标字符串2。
1 ≤ N ≤ 100
1 ≤ M ≤ 100
0 ≤ K ≤ N


输出描述:
方案数对1000000007取模的结果
示例1

输入

3 2 3
AAA
CCC

输出

1

说明

只有 AAA -> BBB -> CCC 一种方案
示例2

输入

2 2 2
AA
AA

输出

4

说明

AA->BB->AA

AA->BC->AA

AA->CB->AA

AA->CC->AA

4种方案
#include<iostream>
#include<string>
using namespace std;
const int f=1000000007;
long long dp[105][105]={0}, C[105][105], pow2[105];
int ct_same(string s1, string s2){
    int ans=0;
    for(int i=0;i<s1.length();i++){
        if(s1[i]==s2[i])ans++;
    }
    return ans;
}
void makeC(int N){
    int mid;
    for(int i=0;i<=N;i++)C[i][0]=1;
    for(int i=1;i<=N;i++){
        mid=i/2;
        for(int j=1;j<=i;j++){
            if(j<=mid) C[i][j] = C[i-1][j-1] * i / j;
            else C[i][j] = C[i][i-j];
        }
    }
}
void make_pow2(int N){
    long long t=1;
    for(int i=0;i<=N;i++){
        pow2[i]=t;
        t = (2*t) % f;
    }
}
int main(){
    int N, M, K;
    cin>>N>>M>>K;
    string s1, s2;
    cin>>s1>>s2;
    int Ns=ct_same(s1, s2);
    makeC(N);
    make_pow2(N);
    dp[1][N-K]=1;
    for(int m=2;m<=M;m++){
        for(int n=0;n<=N;n++){
            long long sum=0, t;
            int K1=max(0, K-N+n), K2=min(K, n);
            for(int i=K1;i<=K2;i++){
                for(int j=0;j<=K-i;j++){
                    t=pow2[i];
                    t = (t * C[n][i]) % f;
                    t = (t * C[N-n][K-i]) % f;
                    t = (t * C[K-i][j]) % f;
                    t = (t * dp[m-1][n+K-2*i-j]) % f;
                    sum = (sum + t) % f;
                }
            }
            dp[m][n]=sum;
        }
    }
    cout<<dp[M][Ns];
    return 0;
}

发表于 2020-08-01 13:34:56 回复(0)
//参考内容https://segmentfault.com/a/1190000021780192 //动态规划递推公式 #include<iostream>
(720)#include<vector>
#include<queue>
(789)#include<string>
#include<functional>
(1307)#define LL long long
using namespace std;
int main() {
    LL n, m, k;
    cin >> n >> m >> k;
    string s1, s2;
    cin >> s1 >> s2;
    int cnt = 0;
    for (int i = 0; i < n; i++)
    {
        if (s1[i] == s2[i])cnt++;
    }
    if (k == 0)
    {
        if (s1.compare(s2) == 0)
            cout << "1" << endl;
        else cout << "0" << endl;
        return 0;
    }
    int mod = 1e9 + 7;
    vector<vector<LL>>C(n + 1, vector<LL>(n + 1, 0));
    vector<vector<LL>>change(n + 1, vector<LL>(n + 1, 0));//the coefficient of change[a-i+j] to change[a]
    //change用来记录系数
        //C[n][m]为组合数, C(n, m)
        //mi[n] = 1<<n-1;
        vector<LL>mi;
    mi.push_back(1);
    for (int i = 0; i <= k; i++)
    {
        mi.push_back(mi.back() % mod << 1);
        //cout << mi.back() << endl;
    }
    for (int i = 0; i < n + 1; i++)
        C[i][0] = 1;
    for (int i = 1; i < n + 1; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
            C[i][j] %= mod;
        }
    }
    for (int a = 0; a <= n; a++)
    {
        for (int i = 0; i <= k; i++)
        {
            int tmp = mi[i] * C[a][i] % mod * C[n - a][k - i] % mod;
            for (int j = 0; j <= k - i; j++)
            {
                if (a - i + j >= 0 && a - i + j <= n)
                    change[a][a - i + j] = (tmp*C[k - i][j]+change[a][a - i + j]) % mod;
            }
        }
    }
    vector<int>ans(n + 1, 0), mm;//由于每一次快捷操作只和上一次结果有关,故降至一维
    ans[n] = 1;
    while (m--)
    {
        mm.clear();
        for (int i = 0; i <= n; i++)
        {
            int tmp = 0;
            for (int j = 0; j <= n; j++)
            {
                tmp = (change[i][j] * ans[j]+tmp) % mod;
            }
            mm.push_back(tmp);
        }
        ans = mm;
    }

    cout << ans[cnt] << endl;
}


发表于 2020-03-04 10:09:59 回复(0)