BZOJ4737: 組合數問題 數位DP+LUCAS定理
阿新 • • 發佈:2018-12-09
Descripition 如果給定n,m和k,對於所有的0≤i≤n,0≤j≤min(i,m)有多少對(i,j)滿足C(i,j)是k的倍數。
Sample Input 3 23 23333333 23333333 233333333 233333333 2333333333 2333333333
Sample Output 851883128 959557926 680723120
挺強的,這題。 我們想一下其實C(i,j)%k==0就OK嗎。 你就lucas一下式子就可以把n,m變成一個k進位制的數, n由a1,a2,a3,…,an,m由b1,b2,b3,…,bn構成。 C(n,m)就等於C(a1,b1) * C(a2,b2) * … * C(an,bn) 如果要滿足C(i,j)%k==0,就只要有一對a1 < b1即可, 根據這個進行數位DP即可
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const LL mod = 1000000007;
LL f[65][2][2][2][2];
int a[65], b[65], K;
LL dfs(int k, int op1, int op2, int op3, int op4) {
if(k == 0) return op1;
if(f[k][op1][op2][op3][op4] != -1) return f[k][op1][op2][op3][op4];
int limit1 = K - 1; if(!op2) limit1 = a[k];
int limit2 = K - 1; if(!op3) limit2 = b[k];
LL ans = 0;
for(int i = 0; i <= limit1; i++) {
for(int j = 0; j <= limit2; j++) {
if(!op4 && j > i) break;
int h1 = 1, h2 = 1, g = op1, kk = 0;
if (!op2 && i == limit1) h1 = 0;
if(!op3 && j == limit2) h2 = 0;
if(j > i) g = 1;
if(op4 || j != i) kk = 1;
(ans += dfs(k - 1, g, h1, h2, kk)) %= mod;
}
} f[k][op1][op2][op3][op4] = ans;
return ans;
}
int main() {
int T; scanf("%d%d", &T, &K);
while(T--) {
LL n, m; scanf("%lld%lld", &n, &m);
if(m > n) m = n;
int len1 = 0, len2 = 0;
while(n) a[++len1] = n % K, n /= K;
while(m) b[++len2] = m % K, m /= K;
for(int i = len2 + 1; i <= len1; i++) b[i] = 0;
memset(f, -1, sizeof(f));
printf("%lld\n", dfs(len1, 0, 0, 0, 0));
}
return 0;
}