#include using namespace std; typedef long long LL; const int N = 2010; //n的数值上限 int t; //t次查询 int n; //n个数字中 int m; //找m个数字组合 int K; //给定k,求k的倍数 int C[N][N]; //组合数数组 int s[N][N]; //二维前缀和 int main() { //默认初始值-1,之所以初始为-1,是怕默认的0无法描述是模完变成的0,还是天生默认就是0,-1就有这个好处。 memset(C, -1, sizeof C); cin >> t >> k; //预处理杨辉三角形 for (int i = 0; i < N; i++) { //base case C[i][0] = C[i][i] = 1; //组合数C(n,0)=1 组合数C(n,n)=c(n,0)=1 //递推生成其它组合数 //因为是求组合数C(A,B),那么A一定要大于等于B,否则就不对了。 //所以,j的循环范围最大就只能是i for (int j = 1; j < i; j++)//因为一头一尾j-->0和i都被手动设置了1,所以循环的范围就是中间剩下的了。 C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % k;//因为C数组中已有的数据都是被%k后存入的, // 所以这里做加法前不用再%,再%也是那么回事,反而速度更慢了。 } //标准的二维前缀和 for (int i = 1; i < N; i++) for (int j = 1; j < N; j++) s[i][j] = (C[i][j] == 0 ? 1 : 0) + s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1]; //处理t次询问 while (t--) { cin >> n >> m; cout << s[n][m] << endl; } }