vp的时候写这题的时候一直想的是状态压缩,实际上我们不需要关心当前状态有哪些数字,只需要关注当前不同的数字个数,于是状态从2^10变成10,然后我们还需要两个状态来表示当前状态和下界、上界的关系。这题用记忆化搜索会比较好写,如果说后面的数字可以任意选并且我们之前算过的话就可以直接返回。
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
const int N=2e5+10,mod=1e9+7;
typedef long long LL;
int f[N][10][2][2];
//f[i][j][k][l]:前i位有j个不同的数,
//k标记这i-1位是否和L的前i-1位都相同,l标记是否和R的前i-1位相同
//方案数
int st[10];
int n,A;
string L,R;
int dfs(int u,int cnt,int f1,int f2)
{
int &v=f[u][cnt][f1][f2];
if(f1==0&&f2==0&&v!=-1) return v; //后面的位可以任意选的时候再返回
if(u==0) return cnt==A;
if(cnt>A) return 0;
int l=f1?L[u]-'0':0,r=f2?R[u]-'0':9;
LL res=0;
for(int x=l;x<=r;x++)
{
st[x]++;
if(st[x]==1) res=(res+dfs(u-1,cnt+1,f1&(x==(L[u]-'0')),f2&(x==(R[u]-'0'))))%mod;
else res=(res+dfs(u-1,cnt,f1&(x==(L[u]-'0')),f2&(x==(R[u]-'0'))))%mod;
st[x]--;
}
return v=res;
}
int main()
{
ios;
cin>>n>>L>>R>>A;
reverse(L.begin(),L.end());reverse(R.begin(),R.end());
L=" "+L,R=" "+R;
memset(f,-1,sizeof f);
cout<<dfs(n,0,1,1)<<endl;
return 0;
}