數位dp(洛谷2657)


步驟:
1.init()預處理出dp數組.dp[i][j]表示數位長度爲i的最高爲j的數字中的windy數的個數.則dp[i][j]=sum(dp[i-1][k]),0<=k<=9&&abs(k-j)>=2
2.寫出計算[1,x]的windy數個數的函數cal(int x).
假設x爲2345,則先算出[1,1000),再算[1000,2000),再算[2000,2300),[2300,2340),[2340,2345),2345.
3.求[a,b]的windy數,就是求cal(b)-cal(a-1).

主要代碼:


public class Main {
	static int dp[][]=new int[20][10];
	//dp[i][j]存儲位數爲i的最高位爲j的數字中的windy數。則dp[i][j]=sum(dp[i-1][k]),9>=k>=0,|k-j|>=2
	static void init() {//預處理出dp數組
		for(int i=0;i<=9;i++) {
			dp[1][i]=1;
		}
		for(int i=2;i<=12;i++) {
			for(int j=0;j<=9;j++) {
				for(int k=0;k<=9;k++) {
					if(Math.abs(j-k)>=2) {
						dp[i][j]+=dp[i-1][k];
					}
				}
				
			}
		}
	}
	static int cal(int x) {//計算[0,x]之間的windy數
		int res=0;
		int s[]=new int[20];
		int len=0;
		//特判,如果x=0
		if(x==0) {
			return 0;
		}
		while(x>0) {
			s[++len]=x%10;
			x/=10;
		}
		//例如x=2345,先算出[1,1000)的windy數
		for(int i=1;i<len;i++) {
			for(int j=1;j<=9;j++) {
				res+=dp[i][j];
			}
		}
		//計算[1000,2000)的
		for(int i=1;i<s[len];i++) {
			res+=dp[len][i];
		}
		
		//計算[2000,2345]的
		for(int i=len-1;i>=1;i--) {
			for(int j=0;j<s[i];j++) {
				if(Math.abs(j-s[i+1])>=2) {
					res+=dp[i][j];
				}
			}
			//判斷2345是不是windy數
			if(i==1&&Math.abs(s[i]-s[i+1])>=2) {
				res+=1;
			}
			//如果當前位與高一位相差不超過2,直接break;
			if(Math.abs(s[i]-s[i+1])<2) {
				break;
			}
		}
		return res;
	}
	public static void main(String args[]) {
		InputReader sc=new InputReader(System.in);
		PrintWriter out=new PrintWriter(System.out);
		int a,b;
		a=sc.nextInt();
		b=sc.nextInt();
		init();
		int res=cal(b)-cal(a-1);
		out.println(res);
		out.flush();
		out.close();
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章