时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld题目描述
You are given two strings s and t composed by digits (characters '0' ∼\sim∼ '9'). The length of s is n and the length of t is m. The first character of both s and t aren't '0'.
Please calculate the number of valid subsequences of s that are larger than t if viewed as positive integers. A subsequence is valid if and only if its first character is not '0'.
Two subsequences are different if they are composed of different locations in the original string. For example, string "1223" has 2 different subsequences "23".
Because the answer may be huge, please output the answer modulo 998244353.输入描述:
The first line contains one integer T, indicating that there are T tests. Each test consists of 3 lines. The first line of each test contains two integers n and m, denoting the length of strings s and t. The second line of each test contains the string s. The third line of each test contains the string t. * 1≤m≤n≤30001 \le m \le n \le 30001≤m≤n≤3000.* sum of n in all tests ≤3000\le 3000≤3000.
* the first character of both s and t aren't '0'.
输出描述:
For each test, output one integer in a line representing the answer modulo 998244353.示例1
输入
复制
3 4 2 1234 13 4 2 1034 13 4 1 1111 2输出
复制
9 6 11说明
For the last test, there are 6 subsequences "11", 4 subsequcnes "111" and 1 subsequence "1111" that are valid, so the answer is 11.
题目链接:
链接:https://ac.nowcoder.com/acm/contest/885/G?&headNav=acm
题意:
给你两个字符串s、t,让你求s所有子串转化成整数的值大于t转换为整数的值的个数。
题解:
首先两种情况,
- s字串长度大于t一定符合,枚举第一个字符位置,后面挨着取就好,这是组合数学。
- 然后第二种就是和t位数相等的情况,这里要用到dp来做。
dp部分如何解决呢,定义
dp[i][j]:s长度为j的后缀有多少长为i的子序列大于t长度为i的后缀个数。首先肯定是 dp[i][j]+=dp[i][j-1]
如果 s[n-j+1]>t[m-i+1],即s长为j的后缀的第一个字符大于t长为i的后缀的第一个字符,那么s在后面的j-1个字符中挑出i-1个也可。
如果 s[n-j+1]=t[m-i+1],那么dp[i-1][j-1]的就行了。
代码:
#include<cstdio>
const int MAX_N = 3005;
const int MOD = 998244353;
int n, m;
char s[MAX_N], t[MAX_N];
long long C[MAX_N][MAX_N];
void ADD(long long &x, long long v) {
x += v;
if(x >= MOD) x -= MOD;
}
void pre() {//组合数初始化
for(int i = 0;i < MAX_N; i++) {
C[i][0] = 1;
for(int j = 1;j <= i; j++) {
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
if(C[i][j] >= MOD) C[i][j] -= MOD;
}
}
}
long long dp[MAX_N][MAX_N];
void solve(){
long long an = 0;
for(int i = n - 1; i >= 0; i--) {//这里先把长于t的所有组合相加
if(s[i] != '0') {
for(int j = m; j <= n - i - 1; j++) {
ADD(an, C[n - i - 1][j]);
}
}
}
for(int j = 0; j <= n; j++) {
for(int i = 0; i <= m; i++) {
dp[j][i] = 0;
}
}
for(int i = m - 1; i >= 0; i--) {
for(int j = n - 1; j >= 0; j--) {
ADD(dp[j][i], dp[j + 1][i]);
if(s[j] > t[i]) {//位数一样,但s当前位》t当前位,加上s后所有组合
ADD(dp[j][i], C[n - j - 1][m - i - 1]);
}
else if(s[j] == t[i]) {//位数一样,s当前位==t当前位,直接加上上次的,继续判断后一位
ADD(dp[j][i], dp[j + 1][i + 1]);
}
}
}
ADD(an, dp[0][0]);
printf("%lld\n", an);
}
int main() {
pre();
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
scanf("%s%s", s, t);
solve();
}
return 0;
}