夏令营提高班上午上机测试 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(‘\n‘);
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(‘\n‘);
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 == ‘\r‘ || c == ‘\n‘);
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\n"); 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\n", f[k][n]);
64 }

哇今天的解题报告好短。。

时间: 2024-11-09 13:11:06

夏令营提高班上午上机测试 Day 4 解题报告的相关文章

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

今天的题的确水.T3还是一道NOIP原题. 嘛,多刷点水题也不是什么坏事嘛. 说来也快,夏令营结束了整一星期了呢.大家也都回到了日常的暑假生活呢. 今天学业水平测试出成绩了...嗯结果还算满意呢,至少达到了预期目标. NOIP这边,还要继续努力啊. 还好,这次我找到我的代码了.每道题我都会把我当时写的代码和GTY哥哥提供的std都贴出来,方便大家批判我巨丑无比的代码(删 好了来说一下Day3的题解. T1:十字架 题目描述 小 D 是虔诚的嘟嘟教徒.现在小 G 送他了一幅著名画家芬达奇的作品.这

真正的入门—提高班的学习

[背景] 自从前年,也就是2013年9月1日进入提高班,到现在,到今天已经度过了526个夜晚.12624个小时.757440分钟!昨天对于计算机的学习有了一些特殊的认识,今天对于英语的学习也差不多出现了相同的认识,真的感觉自己入门了!至于如何入门,您请往下看: [计算机] 前几天开始了自己的计算机二级考试(C++),遵循三步走的战略(略读知宏观.详读知内容.做题看实战).第一阶段结束之后,稍作总结就开始了第二阶段的学习,因为我们小团队采用化整为零细分学习的方法,每小组三个人,进行第二遍的学习,当

数据结构上机测试2-1:单链表操作A (顺序建表+关键字删除)

数据结构上机测试2-1:单链表操作A Time Limit: 1000MS Memory limit: 4096K 题目描述 输入n个整数,先按照数据输入的顺序建立一个带头结点的单链表,再输入一个数据m,将单链表中的值为m的结点全部删除.分别输出建立的初始单链表和完成删除后的单链表. 输入 第一行输入数据个数n: 第二行依次输入n个整数: 第三行输入欲删除数据m. 输出 第一行输出原始单链表的长度: 第二行依次输出原始单链表的数据: 第三行输出完成删除后的单链表长度: 第四行依次输出完成删除后的

如何提高短平快项目的测试效率?

                         如何提高短平快项目的测试效率?                                                    研发资深顾问  杨学明   最近几年,笔者在全国各地包括深圳,北京,上海,杭州,武汉,济南等大中城市开设了近百场测试公开课程,也帮助许多创新型企业进行了产品测试或软件测试管理的内训,大的企业有中航工业.中科院.中国电力研究院.华立仪表.深圳迈瑞等等,也有一些中小型的企业,总体来说,目前中国国内的各公司的测试体系还不

忆在提高班的这4年

伴随着2014年金秋9月的来临,进入提高班学习的第4个年头已结束.在这个大集体里,回顾一下,这些年自己的生活和学习都有了哪些的收获. 一.学习 (1)计算机 第一阶段:计算机基础知识的学习 练习了打字 快捷键和搜索引擎的使用 常用软件的使用(foxmail,outlook,pomodairo,mindmanager,onenote等) 拆装机的学习 Win7.xp系统安装 这个阶段重点学习了计算机的基础知识.在这段学习过程中了解了很多米老师的学习方法,囫囵吞枣.盲人摸象.快速阅读.番茄工作法.编

今天,Java编程周末提高班(第一期)正式结束

Java编程周末提高班(第一期),走过了近两个月历程,一共有68人次到周末到老师家进行Java学习与交流.近距离的和一群年轻的学习接触,收获很多,特别是对以后教学的改进.在学习的闲暇,大家自己做饭,锻炼了厨艺.而今天,还把整个房子打扫.拖地,连我们家那个垃圾桶.拖把桶.洗手液瓶子都擦得干干净净,谢谢 李晓毅.温明玉.杨洁莹.陈思颖四位同学. 老师的收获: (1)了解到了大一新生.大二学生在学习过程中遇到的困难,及解决方式.合作学习还是未能形成,基本上还是大家各自学习为主. (2)学生编程入门过程

转:如何提高测试用例设计的测试覆盖率

说到测试用例的设计,我想每个有过测试经历的测试工程师都会认为很简单,不就是:按需求或概要设计,得到软件功能划分图,然后据此按每个功能,采用等价类划分.临界值.因果图等方法来设计用例就行了. 但事实上撇开测试数据的设计不谈,仅就测试项来说,我们发现,对同一个项目,有经验的测试人员,在写用例或测试时总会有更多的测试考虑点,从而发现更多的问题:而有些测试人员测试用例的撰写却只有那么三板斧,表面看好象已经把页面所有信息的测试都考虑到了,实际上却还是遗漏了大量测试覆盖点,导致其测试出来的程序总是比较脆弱.

老段带你学鸟哥Linux视频教程 包含基础班+提高班

老段带你学鸟哥Linux视频教程 包含基础班+提高班,附带pdf文档. 目录结构如下: 目录:/2020022-老段带你学鸟哥Linux视频教程 [1.9G] ┣━━老段带你学鸟哥-服务器篇 [1009.4M] ┃ ┣━━0-456-1.flv [64.8M] ┃ ┣━━0-456-2.flv [34.5M] ┃ ┣━━7.flv [26.6M] ┃ ┣━━8.flv [43.9M] ┃ ┣━━9-1.flv [28.4M] ┃ ┣━━9-2.flv [43.4M] ┃ ┣━━11-1.flv

【未完成0.0】Noip2012提高组day2 解题报告

第一次写一套题的解题报告,感觉会比较长.(更新中Loading....):) 题目: 第一题:同余方程 描述 求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解. 格式 输入格式 输入只有一行,包含两个正整数a, b,用一个空格隔开. 输出格式 输出只有一行,包含一个正整数x0,即最小正整数解.输入数据保证一定有解. 样例1 样例输入1 3 10 样例输出1 7 限制 每个测试点1s 提示 对于40%的数据,2 ≤b≤ 1,000: 对于60%的数据,2 ≤b≤ 50,000,000: