[清华集训2016] 组合数问题
https://www.luogu.com.cn/problem/P6669
没看到 k k k为质数想了一年
考虑用总的减去不是 k k k的倍数的
k k k为质数就可以套用卢卡斯定理,然后把 n , m n,m n,m 按照 k k k进制拆分后,数位DP,保证任意时刻不存在 ( i j ) = 0 即 i < j \binom{i}{j}=0即i<j (ji)=0即i<j即可
就是一个简单的数位DP
code:
#include<bits/stdc++.h>
#define ll long long
#define N 20005
#define mod 1000000007
using namespace std;
ll f[N][2][2], n, m;
int a[N], b[N], t, p;
ll dfs(int x, int o1, int o2) {
if(!x) return 1;
if(f[x][o1][o2] != -1) return f[x][o1][o2];
ll &ret = f[x][o1][o2];
ret = 0;
int lim1 = o1? a[x] : p - 1, lim2 = o2? b[x] : p - 1;
for(int i = 0; i <= lim1; i ++)
for(int j = 0; j <= lim2 && j <= i; j ++)
ret = (ret + dfs(x - 1, o1 && (i == lim1), o2 && (j == lim2))) % mod;
return ret;
}
void solve() {
memset(f, -1, sizeof f);
scanf("%lld%lld", &n, &m); m = min(n, m);
ll ans = ((m + 1) % mod) * ((m + 2) % mod) % mod * ((mod + 1) / 2) % mod;
ans = (ans + ((n - m) % mod) * ((m + 1) % mod) % mod ) % mod;
int gs = 0, gss = 0;
while(n) a[++ gs] = n % p, n /= p;
while(m) b[++ gss] = m % p, m /= p;
for(int i = gss + 1; i <= gs; i ++) b[i] = 0;
ans = (ans - dfs(gs, 1, 1) + mod) % mod;
printf("%lld\n", ans);
}
int main() {
scanf("%d%d", &t, &p);
while(t --) solve();
return 0;
}