[清华集训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)=0i<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;
}
posted @ 2021-11-10 07:54  lahlah  阅读(39)  评论(0编辑  收藏  举报