密码

题意:

给出一个长度不超过17的数字num,然后排列这个数字所有位数上的数,使得新的数能被17整除,求这新的数中第K(<=17!)小的数。

 

题解:

既然要求出第K小,那么可以从高位到低位一位一位寻找,但是怎么寻找呢?可以计算出从高位到低位能被17整除的方案数,如果大了就进行下一位,小了就变大当前的这一位。

现在的问题就是求出能被17整除的方案数,数据范围很小考虑状态压缩,对于dp[S]表示已经选了所给数的状态为S的位置的数了,但是现在并没法转移因为有余数的限制那么再加一维余数好了,dp[r][S]表示已经选了所给数的状态为S的位置的数组成的新数对17取模为r的方案数。

状态转移 就是将所有状态的后继求和。

 

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
const int N = 20;
const int mod = 17;
#define LL long long
LL dp[20][1<<18], pow[N];
int vis[20][1<<18], n;
char num[N];
LL K;
 
LL calc (int r, LL S, int pos) {
    if (vis[r][S]) return dp[r][S];
    vis[r][S] = 1;
    if (S == 0) {
        if (r == 0) return dp[r][S] = 1;
        else return dp[r][S] = 0;
    }
    int begin = (pos == n) ? 1 : 0;
    for (int i = begin; i <= 9; ++i) {
        for (int j = 0; j < n; ++j) {
            if ((1LL << j) & S && num[j] - '0' == i) {
                int val = ((LL)r + (LL)i * pow[pos-1]) % mod;
                if (val < 0) val += mod;
                dp[r][S] += calc (val, S ^ (1 << j), pos - 1);
                break;
            }
        }
    }
    return dp[r][S];
}
 
void print (int r, LL S, int pos, LL k) {
    if (S == 0) return;
    int begin = (pos == n) ? 1 : 0;
    for (int i = begin; i <= 9; ++i) {
        for (int j = 0; j < n; ++j) {
            if ((1LL << j) & S && num[j] - '0' == i) {
                int val = ((LL)r - (LL)i * pow[pos-1]) % mod;
        if (val < 0) val += mod;
                if (k <= dp[val][S ^ (1 << j)]) {
                    printf ("%d",i);
                    print(val, S ^ (1<<j), pos - 1, k);
                    return;
                }
                else k -= dp[val][S ^ (1 << j)];
            }
        }
    }
}
 
int main () {
    cin >> num >> K;
    n = strlen (num);
    pow[0] = 1;
    for (int i = 1; i <= n; ++i) pow[i] = pow[i-1] * 10;
    calc (0, (1 << n) - 1, n);
    print (0, (1 << n) - 1, n, K);
    return 0;
}

  

  

  

总结:

有点像名次树的感觉~求这种有方向性(高位到低位,名次树就是大小)的第K小,一般会采用计算方案数的方法,看到数据这么小!怎么也要状压才对得起这个数据,对吧?

posted @ 2016-10-26 21:36  xgtao  阅读(170)  评论(0编辑  收藏  举报