1. 程式人生 > >動態規劃之數位動規

動態規劃之數位動規

#include<bits/stdc++.h>
using namespace std;
/*
題意:求給出的A和B之間沒有4和連續的37的數字的個數
1<=A<=B<=2000000000 
*/ 
int f[11][11]={0};
int solve(int x)//從小到大考慮 
{
	int a[11]={0};//分解x 
	while(x)a[++a[0]]=x%10,x/=10;
	
	int ret=0;
	for(int i=1;i<a[0];i++)//列舉位數,不足a[0]位 
	for(int j=1;j<=9;j++)ret+=f[i][j];//列舉最高位數字為j 
	for(int i=1;i<a[a[0]];i++)ret+=f[a[0]][i];//最高位不足a[a[0]] 
	if(a[a[0]]==4)return ret;
	for(int i=a[0]-1;i>=1;i--)//從次高位往下 
	{
		//列舉第i位數字為j,依題意和第i+1位比較 
		for(int j=0;j<a[i]+(i==1);j++)if(j!=4&&!(a[i+1]==3&&j==7))ret+=f[i][j];
		//最大的數字已出現不合法情況則直接返回 
		if(a[i]==4||(a[i+1]==3&&a[i]==7))return ret;
	}
	
	return ret;
}
int main()
{
	//f[i][j]表示i位數字,首位數字為j的情況總數 
	
	for(int i=0;i<=9;i++)if(i!=4)f[1][i]=1;//初始化1位的情況 
	
	for(int i=2;i<=10;i++)//列舉位數 
	for(int j=0;j<=9;j++)//列舉首位//注意在初始化f的過程中前導0是允許的 
	for(int k=0;k<=9;k++)//列舉次位 
	{
		if(j!=4&&k!=4&&!(j==3&&k==7))f[i][j]+=f[i-1][k];
	}
	
	int x,y;
	scanf("%d%d",&x,&y);
	printf("%d\n",solve(y)-solve(x-1));//注意邊界值x也要考慮 
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
/*
題意:求區間[X,Y]內恰好等於K個互不相等的B的整數次冪之和的數的個數
資料範圍:1<=X<=Y<=2^31-1   1<=K<=20   2<=B<=10
思路:
把詢問的數轉換成B進位制xb,則要求的數為每個B進位制數位上有K個1且小於xb的數
設f(i,j,k)表示第i位,首位為j,已經用了k個1的數的個數 
*/
int X,Y,K,B,a[35]={0},f[35][2][25]={0};
int cal(int x)
{
	int ret=0;a[0]=0;
	while(x)a[++a[0]]=x%B,x/=B;//把詢問的數轉換成B進位制 
	
	for(int i=1;i<=a[0]-1;i++)ret+=f[i][1][K];//列舉位數小於a的數 
	
	if(a[a[0]]>1)return ret+f[a[0]][1][K];//最高位已經大於1了,就直接返回了 
	
	int sum=1;//從高位推到低位時,已經用了的1的個數 
	
	for(int i=a[0]-1;i>=1;i--)
	{
		if(a[i]==1)
		{
			ret+=f[i][0][K-sum];//當前位為1則可以加上小於當前位的所有情況 
			sum++;//把當前位為1的情況加上 
		}
		//超過1則包含所有情況 
		else if(a[i])return ret+f[i][0][K-sum]+f[i][1][K-sum];
		
		if(i==1)ret+=f[i][0][K-sum];//???
	}
	
	return ret;
}
int main()
{
	scanf("%d%d%d%d",&X,&Y,&K,&B);
	
	//初始化 
	f[1][0][0]=1;//1位,首位為0、用了0個1的數有一個 
	f[1][1][1]=1;//1位,首位為1、用了1個1的數有一個 
	
	for(int i=2;i<=30;i++)//列舉B進位制數,每個數位全為1或0的數的位數 
	for(int j=0;j<=1;j++)//列舉首位為0或1 
	for(int k=0;k<=K;k++)//列舉已經用了的1的個數 
	for(int t=0;t<=1;t++)//列舉上一個狀態已經用了的1的個數 
		if(k-j>=0)f[i][j][k]+=f[i-1][t][k-j];
	
	cout<<cal(Y)-cal(X-1)<<endl;
	return 0;
}