URAL 2052 Physical Education(数位DP)

题目链接:https://vjudge.net/contest/254142#problem/G

参考题解:https://blog.csdn.net/zearot/article/details/47984379

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define LL __int128
  5 #define ull unsigned long long
  6 #define mst(a,b) memset((a),(b),sizeof(a))
  7 #define mp(a,b) make_pair(a,b)
  8 #define pi acos(-1)
  9 #define pii pair<int,int>
 10 #define pb push_back
 11 const int INF = 0x3f3f3f3f;
 12 const double eps = 1e-6;
 13 const int MAXN = 1e5 + 10;
 14 const int MAXM = 2e6 + 10;
 15 const ll mod = 1e9 + 7;
 16 
 17 int f[15][100], dig[15];
 18 
 19 void init() {
 20     mst(f, 0);
 21     f[0][0] = 1;
 22     for(int i = 1; i <= 10; i++)
 23         for(int j = 0; j <= i * 9; j++)
 24             for(int k = 0; k <= min(9, j); k++)
 25                 f[i][j] += f[i - 1][j - k];
 26 }
 27 
 28 int findall(int pos,int sum,bool limit) {
 29     if(!limit || !pos) return f[pos][sum];
 30     int ans = 0, mx = min(dig[pos], sum);
 31     for(int i = 0; i <= mx; i++)
 32         ans += findall(pos - 1,sum - i,limit && i == dig[pos]);
 33     return ans;
 34 }
 35 
 36 int shu[15];
 37 
 38 void findd(int pos,int sum,int rnk,bool limit) {
 39     if(!pos) return ;
 40     if(!limit) {
 41         int mx = min(9, sum);
 42         for(int i = 0; i <= mx; i++) {
 43             if(f[pos - 1][sum - i] < rnk) rnk -= f[pos - 1][sum - i];
 44             else {
 45                 shu[pos] = i;
 46                 findd(pos - 1,sum - i,rnk,limit);
 47                 return ;
 48             }
 49         }
 50     } else {
 51         int mx = min(dig[pos], sum);
 52         for(int i = 0; i <= mx; i++) {
 53             int temp = findall(pos - 1,sum - i,i == dig[pos]);
 54             if(temp < rnk) rnk -= temp;
 55             else {
 56                 shu[pos] = i;
 57                 findd(pos - 1,sum - i,rnk,i == dig[pos]);
 58                 return ;
 59             }
 60         }
 61     }
 62 }
 63 
 64 int main()
 65 {
 66 #ifdef local
 67     freopen("data.txt", "r", stdin);
 68 //    freopen("data.txt", "w", stdout);
 69 #endif
 70     init();
 71     int n,len = 0;
 72     scanf("%d",&n);
 73     while(n) {
 74         dig[++len] = n % 10;
 75         n /= 10;
 76     }
 77     int ans = 0,sum = 0;
 78     for(int i = 1; i <= len * 9; i++) {
 79         int num = findall(len,i,true);
 80         if(!num) continue;
 81         int l = 1, r = num, num1;
 82         bool flag = false;
 83         while(l <= r) {
 84             int mid = (l + r) >> 1;
 85             findd(len,i,mid,true);
 86             num1 = 0;
 87             for(int j = len; j >= 1; j--) {
 88                 if(!num1 && !shu[j]) continue;
 89                 num1 = num1 * 10 + shu[j];
 90             }
 91             if(sum + mid > num1) l = mid + 1;
 92             else if(sum + mid < num1) r = mid - 1;
 93             else {
 94                 flag = true;
 95                 break;
 96             }
 97         }
 98         if(flag) ans++;
 99         sum += num;
100     }
101     printf("%d
",ans);
102     return 0;
103 }
原文地址:https://www.cnblogs.com/scaulok/p/9683006.html