数位dp uoj275 清华集训2016组合数问题

Posted foreverpiano

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数位dp uoj275 清华集训2016组合数问题相关的知识,希望对你有一定的参考价值。

http://uoj.ac/problem/275

这题不用\(lucas\) 不用\(lucas\)
由于\(k\)是质数
\[C_n^m=\frac{n!}{m!(n-m)!}\]

贡献为\(n!\)\(k\)的因子数量 - \(m!\)\(k\)的因子数量 - \((n-m)!\)\(k\)的因子数量

然后把\(n\) and \(m\) 转换成\(k\)进制
如果\(C_n^m\)不是\(k\)进制数
那么\(m\)的每一位都要小于\(n\)才可以
因为\(m < n\) 如果有一位大于\(n\)前面就要借位
然后就有\(k\)的倍数了

然后dp搞搞 小心爆ll

#include<bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0; char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}
const int mo = 1e9 + 7;
const int inv2 = 1 + mo >> 1;
int T, k, n, m;
int f[233][2];
int a[233], b[233], a_cnt = 0, b_cnt = 0;

inline void U(int &x, int y) {
  x = (x + y) % mo;
  if(x < 0) x += mo;
}

inline int dfs(int pos, int lim, int has) {
  if(!pos) return 1;
  if(!lim && f[pos][has] != -1) return f[pos][has];
  int up = (lim ? a[pos] : k - 1), res = 0;
  // cout << pos << " " << has << "\n";
  for(int i = 0; i <= up; i ++) {
    if(!has || i < b[pos]) {
      U(res, (i + 1) * dfs(pos - 1, lim && (i == up), 0) % mo);
    }
    else {
      U(res, dfs(pos - 1, lim && (i == up), 1));
      U(res, b[pos] * dfs(pos - 1, lim && (i == up), 0) % mo);
    }
  }
  if(!lim) f[pos][has] = res;
  return res;
}

main(void) {
  int T;
  for(read(T), read(k); T --;) {
    read(n); read(m);
    if(m > n) m = n;
    int all = 0;
    int tn = n % mo, tm = m % mo;
    U(all, (1 + tm + 1) % mo * (tm + 1) % mo * inv2 % mo);
    U(all, (tm + 1) % mo * ((tn - tm) % mo + mo) % mo);
    a_cnt = b_cnt = 0;
    memset(f, -1, sizeof f);
    memset(a, 0, sizeof a);
    memset(b, 0, sizeof b);
    for(; n; a[++ a_cnt] = n % k, n /= k);
    for(; m; b[++ b_cnt] = m % k, m /= k);
    int res = dfs(max(a_cnt, b_cnt), 1, 1);
    int ans = all;
    U(ans, -res);
    cout << ans << "\n";    
  }
}

以上是关于数位dp uoj275 清华集训2016组合数问题的主要内容,如果未能解决你的问题,请参考以下文章

uoj#268. 清华集训2016数据交互(动态dp+堆)

UOJ#39. 清华集训2014简单回路 动态规划 插头DP

UOJ268 [清华集训2016] 数据交互 动态DP堆树链剖分线段树

uoj#37/bzoj3812[清华集训2014]主旋律 状压dp+容斥原理

UOJ #86 mx的组合数 (数位DP+NTT+原根优化)

清华集训2016-组合数问题