• F. Igor and Interesting Numbers


    http://codeforces.com/contest/747/problem/F

    cf #387 div2 problem f

    非常好的一道题。看完题,然后就不知道怎么做,感觉是dp,但是不知道怎么枚举。还有就是一般求第k小的思路一般是什么?对这类题目理解的不是很好。

    这道题,跟上一篇的题解里面写的hdu 1002 递增数的题目的解法差不多,但是底层的求解需要花一些时间去推敲!

    不会做,就看官方题解,看不懂说的什么。就从下面的讨论找大神的题解。

    I can describe my solution
    Binary search on what is the answer(mi). So, the problem reduces to counting number of numbers <= mi such that each digit occurs <= t times.
    In fact, we solve a more general problem — find number of numbers of length i such that each digit j occurs <= b[j] times. 0 complicates the matter somewhat but for the time assume that 0 can be placed anywhere and obeys constraint like the normal digits. Then formulate dp[i][j] = number of numbers with i digits and place only digits <= j. Iterate k = how many j digits will be there — 0 to min(i,b[j]) then dp[i][j] = sum((i choose k)*dp[i-k][j-1]). Base cases are simple to write.
    Overall count can be calculated by fixing highest digit(depends on mi) and then a dp call, then next digits etc.. similar to what we do in offline digits dp solution. The prefix digits that are fixed decide what array b is(t — number of times digit has occurred till now).
    Finally for 0, simply calculate for lesser lengths using a similar logic. Checkout my solution for more details.
    Time complexity = O(p^3*d^3) where p=max digits in answer=9 and d=16 and = runs in 15 ms :)

    看完这个之后,思路就清晰很多了,然后接下来就是二分的判断条件,对于给定mi,如何判断比它小的满足要求的数的个数呢? 这个求解思路跟上面写的hdu的1002思路一致, 按长度进行累加和, 因为一个数的长度很小,这里int的16进制表示,最大长度为32/4 = 8, 这个长度很短, 可以通过预处理来快速求解。所以,首先需要解决,长度为k的满足要求的数的个数这个问题!由于题目要求的是每个数出现次数小于等于t, 所以如果按位枚举的话,需要记住每一个数的出现次数,这个好像不容易解决,然后考虑可以使用的数的最大值,使用排列组合的方式,就是上面的思路进行解决。这个问题解决之后, 然后就是对于一个数,先求长度比它小的数的个数,然后求解跟他长度一致的数的个数,依次从高位到低位, 进行求解,枚举每一个数字的方式进行。讲的好乱,我都听不懂了!

    注意上面的复杂度分析:代码运行速度非常快。

    又掌握一种套路,就是上面的dp求解的过程,这个不好思考,求解每个数字出现此小于等于t的数字的个数,使用组合的方式,注意对0的单独处理。

      1 #include <vector>
      2 #include <list>
      3 #include <map>
      4 #include <set>
      5 #include <deque>
      6 #include <queue>
      7 #include <stack>
      8 #include <bitset>
      9 #include <algorithm>
     10 #include <functional>
     11 #include <numeric>
     12 #include <utility>
     13 #include <sstream>
     14 #include <iostream>
     15 #include <iomanip>
     16 #include <cstdio>
     17 #include <cmath>
     18 #include <cstdlib>
     19 #include <cctype>
     20 #include <string>
     21 #include <cstring>
     22 #include <cstdio>
     23 #include <cmath>
     24 #include <cstdlib>
     25 #include <ctime>
     26 #include <string.h>
     27 #include <fstream>
     28 #include <cassert>
     29 using namespace std;
     30 
     31 #define boost ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0)
     32 #define sz(a) int((a).size())
     33 #define rep(i, s, n)  for(int i = s; i <= (n); ++i)
     34 #define rev(i, n, s)  for(int i = (n); i >= s; --i)
     35 #define fore(x, a) for(auto &&x : a)
     36 typedef long long ll;
     37 const int mod = 1000000007;
     38 const int N = 100005;
     39 
     40 int a[9];
     41 int t;
     42 int b[16];
     43 ll dp[8][16];
     44 ll c[9][9];
     45 
     46 ll go(int p, int x) {
     47   if (p == -1) return 1;
     48   if (x == 0) {
     49     if (t - b[x] >= p + 1) return 1;
     50     return 0;
     51   }
     52   ll &res = dp[p][x];
     53   if (res >= 0) return res;
     54   res = 0;
     55   rep(i, 0, min(p + 1,t-b[x])) {
     56     res += c[p+1][i]*go(p - i, x - 1);
     57   }
     58   return res;
     59 }
     60 
     61 char hex(int x) {
     62   if (x >= 10) return 'a' + (x - 10);
     63   return '0' + x;
     64 }
     65 
     66 ll g[9];
     67 
     68 ll f(int x) {
     69   ll res = 0;
     70   memset(b, 0, sizeof(b));
     71   rep(i, 1, 15) {
     72     memset(dp, -1, sizeof(dp));
     73     b[i]++;
     74     res += go(x - 1, 15);
     75     b[i]--;
     76   }
     77   return res;
     78 }
     79 
     80 int main() {
     81 #ifdef loc
     82   if (!freopen((string(FOLDER) + "inp.txt").c_str(), "r", stdin)) {
     83     assert(0);
     84   }
     85   freopen((string(FOLDER) + "out.txt").c_str(), "w", stdout);
     86 #endif
     87   boost;
     88   ll k;
     89   cin >> k >> t;
     90   rep(i, 0, 8) {
     91     c[i][0] = 1;
     92     rep(j, 1, i) {
     93       c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
     94     }
     95   }
     96   rep(i, 0, 8) {
     97     g[i] = f(i);
     98     if (i > 0) g[i] += g[i - 1];
     99   }
    100   ll lo = 1, hi = (1LL << 36) - 1;
    101   while (lo < hi) {
    102     ll mi = (lo + hi) / 2;
    103     ll p = mi + 1;
    104     int td = 0;
    105     rep(i, 0, 8) {
    106       a[i] = p % 16;
    107       p /= 16;
    108       td = i;
    109       if (p == 0) {
    110         break;
    111       }
    112     }
    113     ll tot = td > 0 ? g[td - 1] : 0;
    114     memset(b, 0, sizeof(b));
    115     rev(i, td, 0) {
    116       rep(j,(i==td)?1:0, a[i] - 1) {
    117         b[j]++;
    118         if (b[j] <= t) {
    119           memset(dp, -1, sizeof(dp));
    120           tot += go(i - 1, 15);
    121         }
    122         b[j]--;
    123       }
    124       b[a[i]]++;
    125       if (b[a[i]] > t) break;
    126     }
    127     if (tot >= k) hi = mi;
    128     else lo = mi + 1;
    129   }
    130   vector<int> ans;
    131   while (lo > 0) {
    132     ans.push_back(lo % 16);
    133     lo /= 16;
    134   }
    135   reverse(ans.begin(), ans.end());
    136   fore(x, ans) {
    137     cout << hex(x);
    138   }
    139   cout << endl;
    140   return 0;
    141 }
  • 相关阅读:
    计算机网络
    AJAX
    数组---构建乘积数组
    数组----数组中的重复数字
    字符串---替换空格
    摘要评注The Cathedral & The Bazaar
    BlackJack Strategy
    招聘真题集合
    IIS+PHP+Mysql 返回500,服务器内部资源问题
    熄灯问题(枚举、位运算)
  • 原文地址:https://www.cnblogs.com/y119777/p/6222408.html
Copyright © 2020-2023  润新知