洛谷的题目链接:https://www.luogu.com.cn/problem/P8688
Lucas定理,把\(k|binom{i}{j}\)转换成在k进制下存在某个数位i比j小,再转换成反面计算每一位i都比j大,然后就是经典的数位dp,中间计算的时候可能需要经常求个\(\sum_{i=0}^n \sum_{j=0}^m [i\geq j]\)这样的式子,单独拎出来好写一点x
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
using namespace std;
const int MOD=1e9+7;
const int N=65;
ll f[N],k,d[2][N],g[N][2][2];
ll s(ll n){n%=MOD;return n*(n+1)/2%MOD;}
void add(ll &x,ll y){x+=y;if(x>=y)x%=MOD;}
ll calc(ll n,ll m){return ((s(n+1)-s(max(0ll,n-m)))%MOD+MOD)%MOD;}
void work(ll x,int t){
rep(i,0,N-1)d[t][i]=0;
for(int cnt=0;x;x/=k)d[t][++cnt]=x%k;
}
ll dfs(int pos,bool lim0,bool lim1){
if(pos==0)return 1;
if(g[pos][lim0][lim1]!=-1)return g[pos][lim0][lim1];
ll ans=0;
if(lim0==0&&lim1==0)ans=f[pos];
else if(lim0==0&&lim1==1)ans=((k-d[1][pos])*dfs(pos-1,0,1)%MOD+(s(d[1][pos])+(k-d[1][pos])*d[1][pos]%MOD)%MOD*f[pos-1]%MOD)%MOD;
else if(lim0==1&&lim1==0)ans=((d[0][pos]+1)*dfs(pos-1,1,0)%MOD+s(d[0][pos])*f[pos-1]%MOD)%MOD;
else{
if(d[0][pos]>=d[1][pos])add(ans,dfs(pos-1,1,1));
add(ans,dfs(pos-1,1,0)*min(d[1][pos],d[0][pos]+1)%MOD);
add(ans,dfs(pos-1,0,1)*max(0ll,d[0][pos]-d[1][pos])%MOD);
add(ans,dfs(pos-1,0,0)*calc(d[0][pos]-1,d[1][pos]-1)%MOD);
}
return g[pos][lim0][lim1]=ans;
}
int main(){
fastio;
int T;cin>>T>>k;
f[0]=1;
rep(i,1,N-1)f[i]=1ll*f[i-1]*s(k)%MOD;
while(T--){
ll n,m;
cin>>n>>m;
memset(g,-1,sizeof(g));
work(n,0);work(m,1);
cout<<((calc(n,m)-dfs(64,1,1))%+MOD+MOD)%MOD<<endl;
}
return 0;
}
标签:Lucas,ll,lim1,pos,dfs,蓝桥,2019,ans,MOD
From: https://www.cnblogs.com/yoshinow2001/p/17106834.html