3 0 100 1 10 5 100
Case #1: 1 Case #2: 2 Case #3: 13
题意:求出区间中所有权值小于给定数的个数.
假设dp(i,j)表示i位权值不超过j的个数,然后就可以得到转移方程:
dp(i,j)=dp(i-1,j+x*10^(i-1))(0<=x<=9)
然后数组的初始化只要一次就好了.
<pre style="font-family: 'Courier New'; background-color: rgb(244, 251, 255);"> <pre name="code" class="cpp">#include <bits/stdc++.h> using namespace std; #define mod 1000000007 #define maxn 22 long long a, b; int bit[maxn], l; int dp[9][211111]; #define pow Pow long long pow[maxn]; int sum; long long dfs (int pos, int m1, bool f2) { //当前的位数 之后的权值不能大于m1 是不是可以取到9 if (pos == 0) { //cout << num << ".." << endl; return m1 >= 0; } if (f2 && dp[pos][m1] != -1) { return dp[pos][m1]; } long long Max = (f2 ? 9 : bit[pos]); long long ans = 0; for (long long i = 0; i <= Max; i++) { if (m1-i*pow[pos-1] < 0) continue; ans += dfs (pos-1, m1-i*pow[pos-1], f2 || (i<Max)); } if (f2) dp[pos][m1] = ans; return ans; } long long f (long long num) { l = 0; while (num) { bit[++l] = num%10; num /= 10; } sum = 0; for (int i = 0; a; i++, a/=10) { sum += a%10*pow[i]; } //cout << sum << endl; return dfs (l, sum, 0); } int main () { //freopen ("in.txt", "r", stdin); int t, kase = 0; pow[0] = 1; for (int i = 1; i <= 10; i++) pow[i] = pow[i-1]*2; memset (dp, -1, sizeof dp); scanf ("%d", &t); while (t--) { scanf ("%lld%lld", &a, &b); printf ("Case #%d: %lld\n", ++kase, f (b)); } return 0; }