[BZOJ4737][清華集訓2016]組合數問題(數位 DP )
阿新 • • 發佈:2018-11-23
Address
Solution
根據 Lucas 定理,當
是質數時:
其中
和
分別表示
和
在
進位制意義下第
位的值。
所以問題轉化成有多少對
,
滿足
進位制意義下存在一位
滿足
。
相當於用
減去對於每一位
都滿足
的方案數。
同時如果
則一定存在一位滿足
,所以只需要把
改成
之後,就可以進行數位 DP 了。
表示到第
位,第二維表示是否超過
,第三維表示是否超過
。
大力轉移。複雜度
。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
template <class T>
T Max(T a, T b) {return a > b ? a : b;}
typedef long long ll;
const int N = 105, ZZQ = 1e9 + 7;
inline void add(int &x, int y)
{
x += y;
if (x >= ZZQ) x -= ZZQ;
}
ll n, m;
int T, K, na, nb, a[N], b[N], f[N][2][2], ans;
void work()
{
int i, j, k;
na = nb = 0;
memset(f, 0, sizeof(f));
scanf("%lld%lld", &n, &m);
ll tn = n, tm = m;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
while (n) a[++na] = n % K, n /= K;
while (m) b[++nb] = m % K, m /= K;
For (i, 0, K - 1) For (j, 0, i)
f[1][i > a[1]][j > b[1]]++;
For (i, 2, Max(na, nb)) For (j, 0, K - 1) For (k, 0, j)
if (j < a[i] && k < b[i])
{
add(f[i][0][0], (f[i - 1][0][0] + f[i - 1][0][1]) % ZZQ);
add(f[i][0][0], (f[i - 1][1][0] + f[i - 1][1][1]) % ZZQ);
}
else if (j < a[i] && k > b[i])
{
add(f[i][0][1], (f[i - 1][0][0] + f[i - 1][0][1]) % ZZQ);
add(f[i][0][1], (f[i - 1][1][0] + f[i - 1][1][1]) % ZZQ);
}
else if (j > a[i] && k < b[i])
{
add(f[i][1][0], (f[i - 1][0][0] + f[i - 1][0][1]) % ZZQ);
add(f[i][1][0], (f[i - 1][1][0] + f[i - 1][1][1]) % ZZQ);
}
else if (j > a[i] && k > b[i])
{
add(f[i][1][1], (f[i - 1][0][0] + f[i - 1][0][1]) % ZZQ);
add(f[i][1][1], (f[i - 1][1][0] + f[i - 1][1][1]) % ZZQ);
}
else if (j == a[i] && k == b[i])
{
add(f[i][0][0], f[i - 1][0][0]); add(f[i][0][1], f[i - 1][0][1]);
add(f[i][1][0], f[i - 1][1][0]); add(f[i][1][1], f[i - 1][1][1]);
}
else if (j < a[i] && k == b[i])
{
add(f[i][0][0], (f[i - 1][0][0] + f[i - 1][1][0]) % ZZQ);
add(f[i][0][1