洛谷 P2822 组合数问题

观察数据特点:

  1. n ≤ 2000 n\le 2000 n2000
    而且理论上会访问到低于 ( n m ) n\choose m (mn)的每一种可能
    所以应该全部都要算好
    可以用杨辉三角来算啦
  2. k k k是固定的
    (说实话看到这个条件我以为送分题,再看时发现还是不会做其实是懒
    k ∣ ( i j ) k\mid {i\choose j} k(ji)其实就是 ( i j ) m o d    k = 0 {i\choose j}\mod k =0 (ji)modk=0
    那我们全程取模就好了
    然后每次 1 0 4 10^4 104次询问不可能每次都一个一个算
    观察发现其实问题在求一个二维前缀和
    那基本就是裸的啦

代码倒是不长呢~~

#include
using namespace std;
inline void read(int &x)
{
	x=0;register char c=getchar();
	while(c<48||57<c) c=getchar();
	for(;48<=c&&c<=57;c=getchar()) x=x*10+(c&15);
}
int a[2001][2001],ans[2001][2003],k;
void init()
{
	a[0][0]=1;
	for(int i=1;i<=2000;i++)
	{
		a[i][0]=1;
		for(int j=1;j<=i;j++)
		{
			a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;
			ans[i][j]=ans[i][j-1]+ans[i-1][j]-ans[i-1][j-1]+(a[i][j]==0);
		}
		ans[i][i+1]=ans[i][i];//这个地方要注意:下一行的最后一个数需要加上
	}
}
int main()
{
	int T;read(T);read(k);
	init();
	int n,m;
	while(T--)
	{
		read(n);read(m);
		if(m>n)m=n;
		printf("%d\n",ans[n][m]);
	}
	return 0;
}

你可能感兴趣的:(做题笔记)