1. 程式人生 > 實用技巧 >Codeforces 582D. Number of Binominal Coefficients 題解

Codeforces 582D. Number of Binominal Coefficients 題解

題目連結:D. Number of Binominal Coefficients

題目大意:洛谷


題解:首先根據摩默爾定理,可以得知\(\binom{a+b}{a}\)就是\(p\)進位制下的\(a+b\)的進位次數,所以可以用數位 DP 解決,設定的狀態是\(f_{i,j,0/1,0/1}\)表示前\(i\)個數,進位\(j\)次,當前是否等於上屆,當前是否有來自下一位的進位,然後非常非常麻煩的轉移(花了我一個下午),然後就結束了。

程式碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
void read(int &a){
	a=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		a=(a<<1)+(a<<3)+(c^48);
		c=getchar();
	}
}
typedef long long ll;
const int Maxn=10000;
const int Mod=1000000007;
int p,q,n,m,len;
int a[Maxn+5];
int b[Maxn+5];
char s[Maxn+5];
int f[2][Maxn+5][2][2];
int div(int x){
	ll num=0;
	len=0;
	for(int i=1;i<=m;i++){
		num=num*10+a[i];
		if(len>0||num>=x){
			a[++len]=num/x;
		}
		num%=x;
	}
	for(int i=len+1;i<=m;i++){
		a[i]=0;
	}
	m=len;
	return num;
}
int main(){
	read(p),read(q);
	scanf("%s",s+1);
	while(s[++m]!='\0');
	m--;
	for(int i=1;i<=m;i++){
		a[i]=s[i]-'0';
	}
	while(m){
		b[++n]=div(p);
	}
	for(int i=1;i<=n;i++){
		a[i]=b[n-i+1];
	}
	if(n==0){
		puts("0");
		return 0;
	}
	f[0][0][1][0]=1;
	for(int i=1;i<=n;i++){
		int tmp_0=1ll*p*(p+1)/2%Mod,tmp_1=1ll*p*(p-1)/2%Mod,tmp_2=1ll*a[i]*(a[i]+1)/2%Mod,tmp_3=1ll*a[i]*(a[i]-1)/2%Mod,tmp_4=1ll*a[i]*(p+p-a[i]-1)/2%Mod,tmp_5=1ll*a[i]*(p+p-a[i]+1)/2%Mod;
		memset(f[1],0,sizeof f[1]);
		for(int j=0;j<i;j++){
			f[1][j][0][0]=(f[1][j][0][0]+1ll*f[0][j][0][0]*tmp_0+1ll*f[0][j][1][0]*tmp_2)%Mod;
			f[1][j][0][1]=(f[1][j][0][1]+1ll*f[0][j][0][0]*tmp_1+1ll*f[0][j][1][0]*tmp_3)%Mod;
			f[1][j][1][0]=(f[1][j][1][0]+1ll*f[0][j][1][0]*(a[i]+1))%Mod;
			f[1][j][1][1]=(f[1][j][1][1]+1ll*f[0][j][1][0]*a[i])%Mod;
			f[1][j+1][0][0]=(f[1][j+1][0][0]+1ll*f[0][j][0][1]*tmp_1+1ll*f[0][j][1][1]*tmp_4)%Mod;
			f[1][j+1][0][1]=(f[1][j+1][0][1]+1ll*f[0][j][0][1]*tmp_0+1ll*f[0][j][1][1]*tmp_5)%Mod;
			f[1][j+1][1][0]=(f[1][j+1][1][0]+1ll*f[0][j][1][1]*(p-a[i]-1))%Mod;
			f[1][j+1][1][1]=(f[1][j+1][1][1]+1ll*f[0][j][1][1]*(p-a[i]))%Mod;
		}
		swap(f[0],f[1]);
	}
	int ans=0;
	for(int i=q;i<=n;i++){
		ans=(ans+f[0][i][0][0])%Mod;
		ans=(ans+f[0][i][1][0])%Mod;
	}
	printf("%d\n",ans);
	return 0;
}