微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

洛谷P6669 组合数问题

传送门

题目描述

组合数 C_n^mC
n
m

表示的是从 nn 个物品中选出 mm 个物品的方案数。举个例子,从 (1,2,3)(1,2,3) 三个物品中选择两个物品可以有 (1,2),(1,3),(2,3)(1,2),(1,3),(2,3) 这三种选择方法。根据组合数的定义,我们可以给出计算组合数 C_n^mC
n
m

的一般公式:

C_n^m=\dfrac{n!}{m!(n-m)!}C nm = m!(n−m)!n!

其中 n!=1×2×⋯×nn!=1×2×⋯×n。(额外的,当 n=0n=0 时,n!=1n!=1)

小葱想知道如果给定 n,mn,m 和 kk,对于所有的 0≤i≤n,0≤j≤\min(i,m)0≤i≤n,0≤j≤min(i,m) 有多少对 (i,j)(i,j) 满足 C^j_iC
i
j

是 kk 的倍数。

答案对 10^9+710
9
+7 取模。

输入格式

第一行有两个整数 t,kt,k,其中 tt 代表该测试点总共有多少组测试数据。

接下来 tt 行每行两个整数 n,mn,m。

输出格式
tt 行,每行一个整数代表所有的 0≤i≤n,0≤j≤\min(i,m)0≤i≤n,0≤j≤min(i,m) 中有多少对 (i,j)(i,j) 满足 C^j_iC
i
j

是 kk 的倍数。

输入输出样例

输入 #1复制
1 2
3 3
输出 #1复制
1
输入 #2复制
2 5
4 5
6 7
输出 #2复制
0
7
输入 #3复制
3 23
23333333 23333333
233333333 233333333
2333333333 2333333333
输出 #3复制
851883128
959557926
680723120

说明/提示

样例 11 解释
在所有情况中,只有 C_{2}^{1}=2C
2
1

=2 是 22 的倍数。

限制与约定

对于 20%20% 的测试点,1≤n,m≤1001≤n,m≤100;

对于另外 15%15% 的测试点,n≤mn≤m;

对于另外 15%15% 的测试点,k=2k=2;

对于另外 15%15% 的测试点, m\le10m≤10;

对于 100%100% 的测试点, 1≤n,m≤10^{18}1≤n,m≤10
18
,1≤t,k≤1001≤t,k≤100,且 kk 是一个质数。

代码

#include <queue>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;

char buf[1 << 23],*p1 = buf,*p2 = buf,obuf[1 << 23],*O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf,1,1 << 21,stdin),p1 == p2) ? EOF : *p1 ++)
#define putchar(x) *O ++ = x

template<typename T>void read(T &x) {
	x = 0;T f = 1;char ch = getchar();
	while (!isdigit(ch)) {if (ch == '-') f = -1;ch = getchar();}
	while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}
	x *= f;
}
int read() {
	int x = 0, f = 1;char ch = getchar();
	while (!isdigit(ch)) {if (ch == '-') f = -1;ch = getchar();}
	while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}
	return x * f;
}
template<typename T>void print(T x) {
	if (x < 0) putchar('-'),x = -x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + '0');
}

template<typename T>T Abs(T x) {return x < 0 ? -x : x;}
template<typename T>T Min(T x,T y) {return x < y ? x : y;}
template<typename T>T Max(T x,T y) {return x > y ? x : y;}
template<typename T>void Swap(T &x,T &y) {T z = x;x = y;y = z;}

const int MOD = 1e9 + 7;

long long n,m;
int t,k,tot1,tot2;
int b[65],c[65];
int f[65][2][2][2][2];

int dfs(int len,int up1,int up2,int app,int can) {
	if (!len) return app;
	if (~f[len][up1][up2][app][can]) return f[len][up1][up2][app][can];
	int mdig1 = up1 ? b[len] : k - 1;
	int mdig2 = up2 ? c[len] : k - 1;
	int res = 0;
	for (int i = 0 ; i <= mdig1 ; ++ i) {
		for (int j = 0 ; j <= mdig2 ; ++ j) {
			if (j > i && !can) continue;
			res += dfs(len - 1,up1 && i == mdig1,up2 && j == mdig2,app || (j > i),can || (i > j));
			res = res > MOD ? res - MOD : res;
		}
	}
	return f[len][up1][up2][app][can] = res;
}

int DP(long long x,long long y) {
	memset(f,-1,sizeof f);
	if (y > x) y = x;
	memset(b,0,sizeof b);
	memset(c,0,sizeof c);
	tot1 = tot2 = 0;
	while (x) b[++ tot1] = x % k,x /= k;
	while (y) c[++ tot2] = y % k,y /= k;
	return dfs(tot1,1,1,0,0);
}

int main () {
	read(t);read(k);
	while (t --) {
		read(n);read(m);
		print(DP(n,m)),putchar('\n');
	}
	fwrite(obuf,O - obuf,1,stdout);
	return 0;
}

原文地址:https://www.jb51.cc/wenti/3286374.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐