CF一战让我觉得很疲倦,所以今天感觉很慢。
昨天解D题时候,因为太累,根本连题目都没看,今天看了之后感觉不会做,听闻是数位DP问题。
有某神说过,DP的功力建立在刷过的题上,我真的毫无功力可言。
介绍大家一个很不错的文章。
中学生写的啊!瞬间觉得自己弱爆了……
http://wenku.baidu.com/link?url=q4atTAoZVGlV6sfo0fhED06ogbktY38_TZkGWLkuOpTRiqyI-eDyarkTeL10fv2GdUe53DMIloZ_sD0gZF6xK1ljbcJH1NlLgdyh4aVcGXi
完全根据文章所说的写,毫无问题,一次AC……
/*******************************************************************************/ /* OS : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux * Compiler : g++ (GCC) 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) * Encoding : UTF8 * Date : 2014-04-07 * All Rights Reserved by yaolong. *****************************************************************************/ /* Description: *************************************************************** *****************************************************************************/ /* Analysis: ****************************************************************** *****************************************************************************/ /*****************************************************************************/ #include<iostream> #include<cstdio> #include<cstring> using namespace std; long long dp[40][40]; long a[33]; void init(){ dp[0][0]=1 ;//dp[i][j],表示i位,j个1的数的个数,dp[i][j]=dp[i-1][j]+dp[i-1][j-1] 即第i位为1,第i位为0两种情况 for(long i=1;i<=31;i++){ dp[i][0]=dp[i-1][0]; //0个1的情况,等于第i位不是0的即dp[i-1][0]. for(long j=1;j<=i;j++){ dp[i][j]=dp[i-1][j]+dp[i-1][j-1]; } } } long cal(long x,long k){ long cnt=0,ans=0; for(long i=31;i>0;i--){ //高位开始运算 if(x&(1<<i)){ cnt++; if(cnt>k) break; x=x^(1<<i); //抹掉x的目前最高位 } if((1<<(i-1))<=x){ ans+=dp[i-1][k-cnt]; } } if(cnt+x==k) ans++; //本身 return ans; } long turn(long n,long B){ long i=0,j,res=0; while(n){ a[++i]=n%B; //从1开始末位 n/=B; } j=i; //最高位 while(a[i]<=1){ //高位递减 i--; } while(i>=1){ //将右边全部赋值为1 a[i]=1; i--; } while(j>=1){ res=a[j]+(res<<1); j--; } return res; } long fun(long n,long k,long b){ long X=turn(n,b); return cal(X,k); } int main(){ long X,Y,K,B; long res; init(); while(cin>>X>>Y>>K>>B){ res=fun(Y,K,B)-fun(X-1,K,B); cout<<res<<endl; } return 0; }