题目:
链接:https://ac.nowcoder.com/acm/contest/885/G
来源:牛客网
subsequence 1
时间限制: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.
题意:给定一个长度为n的字符串s和一个长度为m的字符串t,s和t都只有字符‘0’到‘9’组成,询问s有几个子序列大于t字符串代表的数字。每个字符的长度为3000。
思路:用容斥定理和lucas算组合数来求解的,对于长度刚好为m的字符串dp求解。dp第一维代表在s字符串中扫到了第i位,dp第二维表示取了j个数字的情况,dp第三位0代表不相等(取的小于t数组),1代表相等(迄今为止都相等)。最后再容斥定理减去取m个数字时比t数组小的的情况数,以及前导0对长度大于m的情况就是答案了。
AC代码:
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━━━━━━━━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=3050;
const int mod=998244353;
ll luc[maxn];
int s[maxn],t[maxn];
int n,m;
ll dp[maxn][maxn][2];//0是不相等,1是相等的情况
void get_luc(ll mod)
{
luc[0]=1;
for(int i=1;i<maxn;i++) luc[i]=(luc[i-1]*i)%mod;
}
ll qk_power(ll a,ll b,ll c)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%c;
b=b>>1;
a=(a*a)%c;
}
return ans;
}
ll lucas(ll n,ll m,ll p)
{
ll ans=1;
while(n&&m)
{
ll a=n%p;ll b=m%p;
if(a<b) return 0;
ans=((ans*luc[a]%p)*(qk_power(luc[b]*luc[a-b]%p,p-2,p)))%p;
n/=p;m/=p;
}
return ans;
}
vector<int> tmp;
int main()
{
get_luc(mod);
int kase;
scanf("%d",&kase);
while(kase--)
{
tmp.clear();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%1d",&s[i]);
for(int i=1;i<=m;i++)
scanf("%1d",&t[i]);
for(int i=1;i<=n;i++)
{
// cout<<"---"<<i<<endl;
if(s[i]==0) tmp.push_back(i);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
dp[i][j][1]=dp[i][j][0]=0;
for(int i=1;i<=n;i++)
{
dp[i][1][0]=dp[i-1][1][0];
dp[i][1][1]=dp[i-1][1][1];
if(s[i]<t[1]) dp[i][1][0]++;
if(s[i]==t[1]) dp[i][1][1]++;
}
/* for(int i=1;i<=n;i++)
{
cout<<dp[i][1][0]<<"--"<<dp[i][1][1]<<endl;
}*/
for(int i=2;i<=n;i++)
{
for(int j=2;j<=i;j++)
{
dp[i][j][1]=dp[i-1][j][1];
dp[i][j][0]=dp[i-1][j][0];
if(s[i]==t[j])
{
dp[i][j][1]=(dp[i][j][1]+dp[i-1][j-1][1])%mod;
dp[i][j][0]=(dp[i][j][0]+dp[i-1][j-1][0])%mod;
}
if(s[i]<t[j]) dp[i][j][0]=(dp[i][j][0]+dp[i-1][j-1][0]+dp[i-1][j-1][1])%mod;
if(s[i]>t[j]) dp[i][j][0]=(dp[i][j][0]+dp[i-1][j-1][0])%mod;
}
}
ll ans=0;
for(int i=1;i<=n;i++)
{
ans=(ans+lucas(n,i,mod))%mod;
}
for(int i=1;i<=m-1;i++)
{
ans=(ans-lucas(n,i,mod)+mod+mod)%mod;
}
ans=(ans-dp[n][m][1]-dp[n][m][0]+mod)%mod;
for(int i=0;i<(int)tmp.size();i++)
{
int x=tmp[i],t=n-x;
if(t>=m)
{
for(int j=m;j<=t;j++)
{
ans=(ans-lucas(t,j,mod)+mod)%mod;
}
}
else break;
}
printf("%lld\n",ans);
}
return 0;
}