题解 P8688 【[蓝桥杯 2019 省 A] 组合数问题】
题解
首先
观察到
对于一个组合数模一个质数,可以想到
在使用
具体地,我们把
其中,
在这个式子中我们认为当
我们随便选取其中某一项,可以发现
接着发现要存在至少一个
这题到这里其实已经很容易解决了。我们只需要将每一对
其中,
分类讨论一下,容易可以得到
每种情形都很简单,但是讨论起来异常麻烦。读者有兴趣可以自行推导。
参考代码
#include<bits/stdc++.h>
#define up(l, r, i) for(int i = l, END##i = r;i <= END##i;++ i)
#define dn(r, l, i) for(int i = r, END##i = l;i >= END##i;-- i)
using namespace std;
typedef long long i64;
const int INF = 2147483647;
const int MAXN= 60 + 3;
const int MOD = 1e9 + 7;
int A[MAXN], B[MAXN], k;
int F[MAXN][2][2];
void add_to(int &a, int b){
a = (a + b) % MOD;
}
int calc(int a, int b){
if(a >= b){
return (1ll * b * (b + 1) / 2 + 1ll * (a - b) * b) % MOD;
} else
return 1ll * a * (a + 1) / 2 % MOD;
}
int dp(int l, bool f, bool g){
if(F[l][f][g] != -1) return F[l][f][g];
F[l][f][g] = 0;
int a = A[l];
int b = B[l];
if(f == true && g == true){
F[l][f][g] = dp(l + 1, true, true) & (a >= b);
} else if(f == true){
add_to(F[l][f][g], 1ll * dp(l + 1, true, true) * min(a + 1, b) % MOD);
add_to(F[l][f][g], 1ll * dp(l + 1, true, false) * (a + 1) % MOD);
} else if(g == true){
if(a - b > 0)
add_to(F[l][f][g], 1ll * dp(l + 1, true, true) * (a - b) % MOD);
add_to(F[l][f][g], 1ll * dp(l + 1, false, true) * (k - b) % MOD);
} else {
add_to(F[l][f][g], 1ll * dp(l + 1, true, true) * calc(a, b) % MOD);
add_to(F[l][f][g], 1ll * dp(l + 1, true, false) * calc(a, k) % MOD);
add_to(F[l][f][g], 1ll * dp(l + 1, false, true) * calc(k, b) % MOD);
add_to(F[l][f][g], 1ll * dp(l + 1, false, false) * calc(k, k) % MOD);
}
return F[l][f][g];
}
i64 qread(){
i64 w = 1, c, ret;
while((c = getchar()) > '9' || c < '0') w = (c == '-' ? -1 : 1); ret = c - '0';
while((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + c - '0';
return ret * w;
}
int main(){
int T = qread(); k = qread();
up(1, T, _){
i64 n = qread(), nn = n; int a = 0;
i64 m = qread(), mm = m; int b = 0;
mm = m = min(n, m);
while(nn) A[++ a] = nn % k, nn /= k;
while(mm) B[++ b] = mm % k, mm /= k;
int c = max(a, b);
up(a + 1, c, i) A[i] = 0;
up(b + 1, c, i) B[i] = 0;
up(1, c, i){
F[i][0][0] = F[i][0][1] = -1;
F[i][1][0] = F[i][1][1] = -1;
}
F[c + 1][1][1] = 1;
F[c + 1][1][0] = 0;
F[c + 1][0][1] = 0;
F[c + 1][0][0] = 0;
int w = 0;
add_to(w, dp(1, 0, 0));
add_to(w, dp(1, 0, 1));
add_to(w, dp(1, 1, 0));
add_to(w, dp(1, 1, 1));
int ans = ((m + 1) % MOD * ((n + 1) % MOD) % MOD - w + MOD) % MOD;
if(m % 2 == 0)
ans = (ans - (m / 2) % MOD * ((m + 1) % MOD) % MOD + MOD) % MOD;
else
ans = (ans - m % MOD * (((m + 1) / 2) % MOD) % MOD + MOD) % MOD;
printf("%d\n", ans);
}
return 0;
}