1. 程式人生 > 遊戲攻略 >《怪物獵人崛起》金獅子招式派生解析

《怪物獵人崛起》金獅子招式派生解析

數位dp

P2657 [SCOI2009] windy 數

題目大意:

不含前導零且相鄰兩個數字之差至少為 \(2\) 的正整數被稱為 windy 數。windy 想知道,在 \(a\)\(b\) 之間,包括 \(a\)\(b\) ,總共有多少個 windy 數?
\(a,b \le 2\times 10^9\)

思路:

\(f[i][j]\)表示一個\(i\)位數,最高位為\(j\),包括的windy數。例如\(f[3][6]\)統計的是\(600~699\)的答案。
統計時依次統計,要注意一些細節。

核心程式碼:

void init(){
	for(long long i=0;i<=9;i++)f[1][i]=1;
	
	for(long long i=2;i<=10;i++){
		for(long long j=0;j<=9;j++){
			for(long long w=0;w<=9;w++){
				if(abs(j-w)<2)continue;
				f[i][j]+=f[i-1][w];
			}
		}
	}
}

long long dp(long long x){
	if(!x)return 0;
	
	long long res=0,ws[15]={0},tot=0,xx=x;
	while(xx>0){
		ws[++tot]=xx%10;
		xx/=10;
	}
	
	bool ok=1;
	ws[tot+1]=999;
	for(long long i=tot;i>=1;i--){
		for(long long j=1;j<=9;j++)res+=f[i-1][j];  // 如果第i位是前導0,記錄i-1位的答案
		if(ok)
			for(long long j=0;j<ws[i];j++)
				if((i!=tot||j!=0)&&abs(ws[i+1]-j)>=2)
					res+=f[i][j];
		if(abs(ws[i]-ws[i+1])<=1)ok=0;  // 此處不能break,例如123,需要統計0-9,10-99的答案 
	}
	long long last=999;
	ok=1;
	while(x>0){
		if(abs(x%10-last)<=1){
			ok=0; break;
		}
		last=x%10; x/=10;
	}
	res+=ok;
	return res;
}

P2602 [ZJOI2010]數字計數

題目大意:

給定兩個正整數 \(a\) 和 bbb,求在 \(\[a,b\]\) 中的所有整數中,每個數碼(digit)各出現了多少次。
\(a,b \le 10^12\)

思路:

直接統計即可,要明白\(f[i][j]\)的意義,\(f[3][6]\)表示\(6000-6999\),不是\(1-6999\)

核心程式碼:

void init(){
	for(LL i=0;i<=9;i++)f[1][i].c[i]=1;
	for(LL i=2;i<=12;i++){
		for(LL j=0;j<=9;j++){
			for(LL w=0;w<=9;w++)
				f[i][0].c[w]+=f[i-1][j].c[w];
		}
		for(LL j=1;j<=9;j++){
			f[i][j].c[0]=f[i][0].c[0];
			for(LL w=1;w<=9;w++)
				f[i][j].c[w]=f[i][0].c[w]+(LL)(j==w)*(t10[i-1]);
		}
		f[i][0].c[0]+=t10[i-1];
	}
}

qwe dp(LL x){
	// special
	if(x==0){
		qwe c;
		for(LL i=0;i<=9;i++)c.c[i]=0;
		c.c[0]=1;
		return c;
	}
	
	// translate x
	LL ws[15],tot=0,xx=x;
	while(x>0){
		ws[++tot]=x%10;
		x/=10;
	}
	
	qwe res;
	//clear
	for(LL i=0;i<=9;i++)res.c[i]=0;
	
	for(LL i=tot;i>=1;i--){
		if(ws[i]>=1){
			for(int j=0;j<ws[i];j++){
				res=res+f[i][j];
				if(i==tot&&j==0){
					for(int w=i-1;w>=1;w--)
						res.c[0]-=t10[w];
				}
			}
		}
		res.c[ws[i]]+=(xx%t10[i-1]+1);  // 別忘了給這一位自己統計上
	}
	return res;
}