列表

详情


NC200627. 芒砀山的神秘数字

描述

巫山老伯所在地芒砀山有神秘数字的出现,世人惊讶。此神秘数字一旦破解,秦皇便可以此长生不老,构建万世天宫。
神秘数字是在一个陨石坠落之时,所产生的。陨石坠落时分为两块,分别落在了芒砀山的南北两侧。导致芒砀山南北两侧皆有一串神秘数字。
现秦始皇派巫山老伯前去解开此神秘数字背后的秘密。
神秘数字南北方的长度分别为n和m。
巫山老伯发现,此两串神秘数字的背后隐藏的秘密是一个数。
巫山老伯发现神秘数字背后的数字就是南方神秘数字串的子序列的值大于北方神秘数字串的值的序列个数。

输入描述

输入T (T<= 10)
输入n m 表示南方神秘数字串的长度和北方神秘数字串的长度。(1<= m <= n <= 3000 )
输入南方神秘数字串
输入北方神秘数字串

输出描述

输出两串神秘数字的背后隐藏的秘密是一个数,并将此数对998244353取模。

示例1

输入:

3
4 2
1234
13
4 2
1034
13
4 1
1111
2

输出:

9
6
11

说明:

第一组样例解释:
比北方神秘数字串大的南方神秘数字串的子序列串有:
14  124 1234 34 23 123 234 134 24

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 137ms, 内存消耗: 416K, 提交时间: 2020-07-15 19:01:44

#include<bits/stdc++.h>
using namespace std;
 
const int mod=998244353;
int i,j,n,m,t,ans,A[3005],B[3005],DP[3005];
int fastpow(long long a,int b)
{
    long long s=1;
    for(;b;b>>=1,a=a*a%mod)if(b&1)s=s*a%mod;
    return s;
}
long long C(int n,int m)
{
    return (long long)A[n]*B[m]%mod*B[n-m]%mod;
}
int main()
{
    char R[3005],T[3005];
    for(A[0]=i=1;i<=3000;i++)A[i]=(long long)A[i-1]*i%mod;
    B[3000]=fastpow(A[3000],mod-2);
    for(i=2999;i>=0;i--)B[i]=(long long)B[i+1]*(i+1)%mod;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%s%s",&n,&m,R+1,T+1);
		ans=0,memset(DP,0,sizeof(DP));
        for(i=1;i+m<=n;i++)
        {
            if(R[i]=='0')continue;
            for(j=m;i+j<=n;j++)ans=(ans+C(n-i,j))%mod;
        }
        for(DP[0]=i=1;i<=n;i++)
			for(j=m;j>=1;j--)
			{
				if(R[i]>T[j]&&n-i>=m-j)ans=(ans+DP[j-1]*C(n-i,m-j)%mod)%mod;
				if(R[i]==T[j])DP[j]=(DP[j]+DP[j-1])%mod;
			}
        printf("%d\n",ans);
    }
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 276ms, 内存消耗: 101752K, 提交时间: 2020-01-18 15:46:46

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod = 998244353;
const int N = 3010;
int t;
int n,m;
char sn[N],sm[N];
ll cal[N][N];
ll dp[N][N];
void pre()
{
	cal[0][0]=1;
	for(int i=1;i<=3000;i++)
	{
		cal[i][0]=cal[i][i]=1;
		for(int j=1;j<i;j++)
		cal[i][j]=(cal[i-1][j-1]+cal[i-1][j])%mod;
	}
}
int main()
{
	pre();
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		scanf("%s",sn+1);
		scanf("%s",sm+1);
		ll ans=0;//用于记录答案
		//计算长度相等的答案 
		dp[0][0]=1;
		for(int i=1;i<=n;i++)
		{
			dp[i][0]=1;
			for(int j=1;j<=m;j++)
			{
				if(sn[i]>sm[j])
				ans=(ans+dp[i-1][j-1]*cal[n-i][m-j]%mod)%mod;
				dp[i][j]=dp[i-1][j];
				if(sn[i]==sm[j])
				dp[i][j]+=dp[i-1][j-1];
				dp[i][j]%=mod;
			}
		}
		//计算长度不相等的答案
		for(int i=1;i<=n;i++)
		{
			if(sn[i]=='0')
			continue;
			for(int j=m;i+j<=n;j++)
			ans=(ans+cal[n-i][j])%mod;
		}
		printf("%lld\n",ans);
	}
}

上一题