subsequence 1

题目链接

题意:给你两个字符串都是数字,让你求第一个字符串的子序列中大于第二个字符串的个数。

思路:dp[i][j] 表示 str1的前i个,匹配 str2的前 j 个的种类数,那么 if(s[i] == t[j]) dp[i][j] = dp[i -1][j] + dp[i - 1][j - 1]; else dp[i][j] = dp[i - 1][j];  对于长度大于 t 的没有前导0的都符合,那么就看长度等于t的就可以了,当匹配到 i, j 的时候,if(s[i] > s[j]) 那么该贡献为:前面匹配j-1的种类数*后面随便选len2-j个,即当前的贡献就为dp[i - 1][j - 1] * C[len1 - i][len2 - j]。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<vector>
#include<queue>
#include<cmath>
#define ll long long
using namespace std;
const int mod=998244353;
char str1[30001],str2[30001];
int dp[3010][3011];
int C[3010][3010];
int main()
{
    int t;
    C[0][0] = C[1][0] = C[1][1] = 1;
    for(int i = 2; i <= 3000; i++) {
        C[i][0] = 1;
        for(int j = 1; j <= i; j++)
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
    }
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        long long sum=0;
        scanf("%d%d",&n,&m);
        scanf("%s%s",str1+1,str2+1);
        int len1=strlen(str1+1);
        int len2=strlen(str2+1);
        for(int i=0;i<=len1;i++)
        dp[i][0]=1;
        for(int i=1;i<=len1;i++)
        {
            for(int j=1;j<=min(len2,i);j++)
            {
                dp[i][j]=dp[i-1][j];
                if(str1[i]==str2[j])
                dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
                if(str1[i]>str2[j])
                {
                    sum=(sum+(ll)dp[i-1][j-1]*C[len1-i][len2-j])%mod;
                }
            }
        }
        for(int i=1;i<=len1;i++) {
            if(str1[i]=='0')
                continue;
            for(int j=len2;j<=len1-i;j++)
                sum=(sum+C[len1-i][j])%mod;
        }
        printf("%lld\n",sum);
    }
}

 

posted @ 2019-08-01 21:33  Ldler  Views(120)  Comments(0Edit  收藏  举报