• 夏令营提高班上午上机测试 Day 4 解题报告


    我要是没记错的话,今天的题难度算挺适中的。
    *标程来自高天宇哥哥
    T1:小G的字符串

     题目描述

    有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的、全由小写英文字母构成的字符串,只能使用 k 种字母。要求满足:

    • 字符串中相邻的两个字母不能相同。
    • 必须出现恰好 k 种不同的字母。

    这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个。

    小 G 太笨啦,不会做这道题,希望你帮帮他。

    输入格式

    输入文件只有两个数字 n; k,含义如题。

    输出格式

    输出文件共一行,输出合法的字典序最小的字符串。

    如果不存在任意一个合法的方案,输出 1。

    样例输入

    7 4

    样例输出

    ababacd

    数据范围

    对于 100% 的数据,1≤n≤105; 1≤k≤26

     
    题目大概的意思是说让我们生成一个字典序最小的字符串,满足相邻字符不相同,并且出现k个不同的字符。
    乍一看无法下手,其实特别特别简单。。
    (表面慌的一匹,实则稳如老狗)
    对于k>2的情况,只需要在前面不断输出ababab……最后把剩下的字符都输出出来就好了。
    这样显然是字典序。
    恶心的是,特殊情况太多。
    k>n,直接-1不用考虑
    k=1,n=1,只输出一个a
    k=1,n>1这个显然-1
    k=2,全都是abababab…
     
     1 #include <cstring>
     2 #include <cstdlib>
     3 #include <iostream>
     4 #include <cmath>
     5 #include <cstdio>
     6 using namespace std;
     7 
     8 int main() {
     9     freopen("str.in", "r", stdin);
    10     freopen("str.out", "w", stdout);
    11     int n, k;
    12     cin >> n >> k;
    13     
    14     if (k > n) {
    15         cout << -1 << endl;
    16         return 0;
    17     }
    18 
    19     if (k == 1) {
    20         if (n > 1)
    21             cout << -1 << endl;
    22         else
    23             cout << "a" << endl;
    24     } else if (k == 2) {
    25         for (int i = 1; i <= n; i++)
    26             if (i % 2) putchar('a');
    27             else putchar('b');
    28         putchar('
    ');
    29     } else {
    30         for (int i = 1; i <= n - (k - 2); i++)
    31             if (i % 2) putchar('a');
    32             else putchar('b');
    33         for (int i = 2; i < k; i++) putchar('a' + i);
    34         putchar('
    ');
    35     }
    36 }
     
    T2:小G的城堡

    题目描述

    小 G 家有一座城堡。城堡里面有 n 个房间,每个房间上都写着一个数字 pi

    小 G 拉着几个小伙伴在城堡里面玩耍,他们约定,如果某个人当前站在 i 房间里面,下一步这个人就会去 pi 房间,再下一步这个人去 ppi 

    为了增加趣味性,小 G 想重新书写每个房间的 pi,以满足:

    • 如果从编号 1 到 k 中的某个房间开始,按照规则走,必须能够走到 1 号房间。特别地,如果从 1 号房间开始走,也要能够走回 1 号房间(至少走一步,如果 p1 = 1,从 1 走到 1 也算合法)。
    • 如果从编号大于 k 的某个房间开始,按照规则走,一定不能走到 1 号房间。

    小 G 想知道,有多少种书写 pi 的方案,可以满足要求。

    输入格式

    输入文件一行两个数字 n; k,含义如题。

    输出格式

    输出文件一个数字,表示合法的方案数。答案对 10+ 7 取模 

    样例输入 1

    5 2

    样例输出 1

    54

    样例输入 2

    7 4

     样例输出 2

    1728

    数据范围

    对于 40% 的数据,1 ≤ n ≤ 8

    对于 70% 的数据,1 ≤ n ≤ 105

    对于 100% 的数据,1 ≤ n ≤ 1018; 1  ≤k ≤min(8,n)。

     
    题目大意:有n个点,每个点有一条出边。要求前k个点能走到1号点,后k个点不能走到一号点,问方案数。
    n<=8
    暴力搜索,看每个点的出边指向哪里,然后检查就好。
    n<=10^5
    我们发现,前k个点肯定和前k个点互相连边。后n-k个点肯定不会连到前k个点里面去。
    所以,我们只要爆搜前k个点连接的方案,然后检查;后n-k个点,只要连的是后n-k个点,爱怎么连怎么连,方案数是(n-k)^(n-k)。最后把两部分方案数乘起来就行。
    n<=10^18
    (n-k)^(n-k)太大?请使用快速幂。
      
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <cstdlib>
     5 #include <iostream>
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 const int mod = 1e9 + 7;
    10 
    11 ll n, k;
    12 ll ans = 0;
    13 
    14 inline ll qe(ll a, ll p) {
    15     ll ans = 1;
    16     a %= mod;
    17     for (; p; p >>= 1, a = a * a % mod)
    18         if (p & 1)
    19             ans = ans * a % mod;
    20     return ans;
    21 }
    22 
    23 int go_loc[10];
    24 
    25 inline bool check() {
    26     static bool vis[10];
    27     memset(vis, 0, sizeof(vis));
    28 
    29     int now = 1;
    30     while (!vis[now]) {
    31         vis[now] = true;
    32         now = go_loc[now];
    33     }
    34     if (now != 1) return false;
    35     for (int i = 1; i <= k; i++)
    36         if (!vis[i]) {
    37             static bool other_vis[10];
    38             memset(other_vis, 0, sizeof(other_vis));
    39             int now = i;
    40             while (!other_vis[now] && !vis[now]) {
    41                 other_vis[now] = true;
    42                 now = go_loc[now];
    43             }
    44             if (!vis[now]) return false;    
    45         }
    46     return true;
    47 }
    48 
    49 void dfs(int now) {
    50     if (now == k + 1) {
    51         if (check()) ans++;
    52         return;
    53     }
    54     for (int i = 1; i <= k; i++) {
    55         go_loc[now] = i;
    56         dfs(now + 1);
    57     }
    58 }
    59 
    60 int main() {
    61     freopen("castle.in", "r", stdin);
    62     freopen("castle.out", "w", stdout);
    63     cin >> n >> k;
    64     dfs(1);
    65     ans = ans * qe(n - k, n - k) % mod;
    66     cout << ans << endl;
    67 }
     
    T3:小G坐电梯

    题目描述

    小 G 来到了著名的 CIGOM 大厦。大厦一共有 n 层,初始的时候小 G 在第 A 层。小 G 特别想去 B 层小 M 的办公室看一看,然而因为安保原因,B 层已经被封锁无法进入。

    但是小 G 既然来了,就想在大厦里面逛一逛。大厦里面有一部电梯,小 G 决定坐 k 次电梯。因为小 G 比较无聊,他给自己设定了这样一个规矩:假如当前他在 x 层,则他要去的下一个楼层 y  x 的楼层差必须要小于 x  B 的楼层差,即|x-y| < |x-B|。每到达一个楼层,小 G 都要记录下来其楼层号。

    当小 G 转完一圈后,他也记录下了 k + 1 个楼层号(可能有重复)。小 G 现在想知道,按照他定下的规矩,一共有多少种可能的楼层号序列?

    输入格式

    输入文件一行,4 个数字 n,A, B, k,含义如题目所述。

    输出格式

    输出一个数字,表示可能的楼层号序列的数量。答案对 109 + 7 取模。

    样例输入 1

    5 2 4 1

    样例输出 1

    2

    样例输入 2

    5 2 4 2

    样例输出 2

    2

    样例输入 3

    5 3 4 1

    样例输出 3

    0

    数据范围

    对于 30% 的数据,2≤ n≤ 8; 1 ≤ k ≤ 8。

    对于 70% 的数据,2 ≤ n 300; 1 ≤ k ≤ 300。

    对于 100% 的数据,2 ≤ n ≤ 5000; 1 ≤k ≤5000; 1≤ A,B≤n; A ≠B

    这个题告诉我们,有n个楼层,走k步。每次走的距离不能超过当前点距离B层的距离。问方案数。
    搜索是显然的,但这个题正解是DP。
    注意到主人公永远不能跨越B层。
    令f[step][i]表示当前是第step步,走到i这个位置的方案数。
    转移(我们以B层下侧为例):
    f[step][i]=f[step-1][1~i-1]+f[step-1][i+1~ k]
    其中,如果i+B为偶数,k=(i+B)/2-1
    i+B为奇数,k=(i+B)/2
    但这样并不能过所有点,因为转移是O(n)的。
    我们要用O(1)的转移。注意我们每次的转移都来自一个连续的区间,而且我们是求和
    来自一个连续的区间,还要求和,读者朋友,您是不是想到了前缀和?
    令sum[step][i]表示f[step][1~i]的和
    还是以B下侧为例
    有f[step][i]=sum[step-1][i-1]+sum[step-1][k]-sum[step-1][i]。
     
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <iostream>
     6 #include <algorithm>
     7 using namespace std;
     8 
     9 typedef long long ll;
    10 const int MAXN = 6000;
    11 const int MOD  = 1000000007;
    12 int f[MAXN][MAXN] = {{0}};
    13 int n, a, b, k;
    14 
    15 inline int getnum()
    16 {
    17     char c; int ans = 0; bool flag = false;
    18     while ((c = getchar()) == ' ' || c == '
    ' || c == '
    ');
    19     if (c == '-') flag = true; else ans = c - '0';
    20     while ((c = getchar()) >= '0' && c <= '9') ans = ans * 10 + c - '0';
    21     return ans * (flag ? -1 : 1);
    22 }
    23 
    24 inline void add(int &a, int b)
    25 {
    26     ll tmp = (ll)a + b;
    27     if (tmp >= MOD) a = (int)(tmp - MOD);
    28     else if (tmp < 0) a = (int)(tmp + MOD);
    29     else a = (int)tmp;
    30 }
    31 
    32 int main()
    33 {
    34     freopen("lift.in", "r", stdin);
    35     freopen("lift.out", "w", stdout);
    36     n = getnum(); a = getnum(); b = getnum(); k = getnum();
    37     if (fabs(a - b) - 1 == 0) { printf("0
    "); return 0; }
    38     for (int i = a; i <= n; i++)
    39         f[0][i] = 1;
    40     for (int step = 1; step <= k; step++)
    41     for (int i = 1; i <= n; i++)
    42         if (i == b) f[step][i] = f[step][i - 1];
    43         else
    44         {
    45             f[step][i] = f[step][i - 1];
    46             if (i < b)
    47             {
    48                 int x = (b + i) / 2;
    49                 if ((b + i) % 2 == 0) x--;
    50                 add(f[step][i], f[step - 1][x]);
    51                 add(f[step][i], -f[step - 1][i]);
    52                 add(f[step][i], f[step - 1][i - 1]);
    53             }
    54             else
    55             {
    56                 int x = (b + i) / 2;
    57                 add(f[step][i], f[step - 1][n]);
    58                 add(f[step][i], -f[step - 1][x]);
    59                 add(f[step][i], -f[step - 1][i]);
    60                 add(f[step][i], f[step - 1][i - 1]);
    61             }
    62         }
    63     printf("%d
    ", f[k][n]);
    64 }
     
     
    哇今天的解题报告好短。。
     
     
    一切无法杀死我的,都将使我变得更加强大。
  • 相关阅读:
    八大排序算法——插入排序(动图演示 思路分析 实例代码java 复杂度分析)
    八大排序算法——冒泡排序(动图演示 思路分析 实例代码java 复杂度分析)
    八大排序算法——选择排序(动图演示 思路分析 实例代码Java 复杂度分析)
    蓝桥杯 算法训练 素因子去重 (java)
    蓝桥杯 每周一练 第一周(3n+1问题)
    第八届蓝桥杯程序设计大赛 国赛 填空题第一题 平方十位数
    拼多多 2018 校招编程题 六一儿童节
    泛型的实质
    JAVA 反射之Method
    JAVA反射之 Field (属性)
  • 原文地址:https://www.cnblogs.com/OIerShawnZhou/p/7411305.html
Copyright © 2020-2023  润新知