[2019上海网络赛F题]Rhyme scheme

题目链接

题意,求出合法的长度为n的字典序第k小字符串,合法的定义为除了最后一位,每一位的取值范围为'A'到'A'+pos-1,而最后一位的取值范围'A'到当前字符串最大值+1。

队友tql,Orz

一开始就想爆搜,但是不知道如何判断当前位为X时的合法字符串个数。然后队友就莽过去了Orz。

大致做法就是类似数位dp的方式预处理出第i位为j时有多少合法字符串,这样求答案时就可以直接判断能否满足第k个,满足就继续搜下去,不满足就k-dp[i][j]。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef __int128 ll;
 4 const int mod = 1e9 + 7;
 5 ll dp[30][30];
 6 int ans[30];
 7 int n; ll k;
 8 ll read() {
 9     ll x = 0, f = 1;
10     char c = getchar();
11     for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
12     for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
13     return x * f;
14 }
15 ll dfs(int pos, int limit) {
16     if (pos == n + 1)return 1;
17     if (dp[pos][limit] != -1)return dp[pos][limit];
18     ll sum = 0;
19     for (int i = 0; i <= limit; i++)
20         sum += dfs(pos + 1, max(limit, i + 1));
21     dp[pos][limit] = sum;
22     return dp[pos][limit];
23 }
24 void solve(int pos, int limit, ll k) {
25     if (pos == n) {
26         for (int i = 0; i < n; i++)
27             printf("%c", ans[i] + 'A');
28         printf("\n");
29         return;
30     }
31     for (int i = 0; i <= limit; i++) {
32         ll lim = max(limit, i + 1);
33         if (dp[pos + 1][lim] >= k) {
34             ans[pos] = i;
35             solve(pos + 1, lim, k);
36             break;
37         }
38         else
39             k -= dp[pos + 1][lim];
40     }
41 }
42 int main() {
43     int t, cnt = 1;
44     scanf("%d", &t);
45     while (t--) {
46         scanf("%d", &n);
47         k = read();
48         for (int i = 0; i <= 26; i++)
49             for (int j = 0; j <= 26; j++)
50                 dp[i][j] = -1;
51         for (int i = 0; i < 30; ++i) dp[n][i] = 1;
52         dfs(0, 0);
53         printf("Case #%d: ", cnt++);
54         solve(0, 0, k);
55     }
56 }

 

posted @ 2019-09-16 09:33  祈梦生  阅读(476)  评论(0编辑  收藏  举报