CodeForces 721B Passwords

密码输入策略分析
本文探讨了一个关于密码输入的问题,分析了在限定条件下输入密码所需的最短及最长时间。通过记录不同长度密码的数量,并考虑错误输入后的等待时间,文章提供了解决这一问题的有效算法。
部署运行你感兴趣的模型镜像

B. Passwords
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Vanya is managed to enter his favourite site Codehorses. Vanya uses n distinct passwords for sites at all, however he can't remember which one exactly he specified during Codehorses registration.

Vanya will enter passwords in order of non-decreasing their lengths, and he will enter passwords of same length in arbitrary order. Just when Vanya will have entered the correct password, he is immediately authorized on the site. Vanya will not enter any password twice.

Entering any passwords takes one second for Vanya. But if Vanya will enter wrong password k times, then he is able to make the next try only 5 seconds after that. Vanya makes each try immediately, that is, at each moment when Vanya is able to enter password, he is doing that.

Determine how many seconds will Vanya need to enter Codehorses in the best case for him (if he spends minimum possible number of second) and in the worst case (if he spends maximum possible amount of seconds).

Input

The first line of the input contains two integers n and k (1 ≤ n, k ≤ 100) — the number of Vanya's passwords and the number of failed tries, after which the access to the site is blocked for 5 seconds.

The next n lines contains passwords, one per line — pairwise distinct non-empty strings consisting of latin letters and digits. Each password length does not exceed 100 characters.

The last line of the input contains the Vanya's Codehorses password. It is guaranteed that the Vanya's Codehorses password is equal to some of his n passwords.

Output

Consider the first sample case. As soon as all passwords have the same length, Vanya can enter the right password at the first try as well as at the last try. If he enters it at the first try, he spends exactly 1 second. Thus in the best case the answer is 1. If, at the other hand, he enters it at the last try, he enters another 4 passwords before. He spends 2 seconds to enter first 2 passwords, then he waits 5seconds as soon as he made 2 wrong tries. Then he spends 2 more seconds to enter 2 wrong passwords, again waits 5 seconds and, finally, enters the correct password spending 1 more second. In summary in the worst case he is able to be authorized in 15 seconds.

Examples
input
5 2
cba
abc
bb1
abC
ABC
abc
output
1 15
input
4 100
11
22
1
2
22
output
3 4
Note

Consider the second sample case. There is no way of entering passwords and get the access to the site blocked. As soon as the required password has length of 2, Vanya enters all passwords of length 1 anyway, spending 2 seconds for that. Then, in the best case, he immediately enters the correct password and the answer for the best case is 3, but in the worst case he enters wrong password of length2 and only then the right one, spending 4 seconds at all.


不要被 he,不要被hei........

题意:

键入 n 行密码,最后给定正确的密码。每次键入错 k 次后需要等待 5 秒后才能继续键入,

问键入密码成功的最短和最长时间。

不明白是不是密码的键入是默认字符串有长到短。


思路:

记录每个长度字符串的个数,记住的就是:长度有短到长键入,最少次数和最多次数见代码

CODE:

/*
                              _,add8ba,
                            ,d888888888b,
                           d8888888888888b                        _,ad8ba,_
                          d888888888888888)                     ,d888888888b,
                          I8888888888888888 _________          ,8888888888888b
                __________`Y88888888888888P"""""""""""baaa,__ ,888888888888888,
            ,adP"""""""""""9888888888P""^                 ^""Y8888888888888888I
         ,a8"^           ,d888P"888P^                           ^"Y8888888888P'
       ,a8^            ,d8888'                                     ^Y8888888P'
      a88'           ,d8888P'                                        I88P"^
    ,d88'           d88888P'                                          "b,
   ,d88'           d888888'                                            `b,
  ,d88'           d888888I                                              `b,
  d88I           ,8888888'            ___                                `b,
 ,888'           d8888888          ,d88888b,              ____            `b,
 d888           ,8888888I         d88888888b,           ,d8888b,           `b
,8888           I8888888I        d8888888888I          ,88888888b           8,
I8888           88888888b       d88888888888'          8888888888b          8I
d8886           888888888       Y888888888P'           Y8888888888,        ,8b
88888b          I88888888b      `Y8888888^             `Y888888888I        d88,
Y88888b         `888888888b,      `""""^                `Y8888888P'       d888I
`888888b         88888888888b,                           `Y8888P^        d88888
 Y888888b       ,8888888888888ba,_          _______        `""^        ,d888888
 I8888888b,    ,888888888888888888ba,_     d88888888b               ,ad8888888I
 `888888888b,  I8888888888888888888888b,    ^"Y888P"^      ____.,ad88888888888I
  88888888888b,`888888888888888888888888b,     ""      ad888888888888888888888'
  8888888888888698888888888888888888888888b_,ad88ba,_,d88888888888888888888888
  88888888888888888888888888888888888888888b,`"""^ d8888888888888888888888888I
  8888888888888888888888888888888888888888888baaad888888888888888888888888888'
  Y8888888888888888888888888888888888888888888888888888888888888888888888888P
  I888888888888888888888888888888888888888888888P^  ^Y8888888888888888888888'
  `Y88888888888888888P88888888888888888888888888'     ^88888888888888888888I
   `Y8888888888888888 `8888888888888888888888888       8888888888888888888P'
    `Y888888888888888  `888888888888888888888888,     ,888888888888888888P'
     `Y88888888888888b  `88888888888888888888888I     I888888888888888888'
       "Y8888888888888b  `8888888888888888888888I     I88888888888888888'
         "Y88888888888P   `888888888888888888888b     d8888888888888888'
            ^""""""""^     `Y88888888888888888888,    888888888888888P'
                             "8888888888888888888b,   Y888888888888P^
                              `Y888888888888888888b   `Y8888888P"^
                                "Y8888888888888888P     `""""^
                                  `"YY88888888888P'
                                       ^""""""""'
*/
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define AC main()
using namespace std;
const int MYDD = 1103;

int AC {
	int n, k, len[MYDD], lenans;
	char a[113];
	scanf("%d %d", &n, &k);

	for(int j = 0; j < MYDD; j++)  len[j] = 0;
	for(int j = 0; j < n + 1; j++) {
		scanf("%s", a);
		if(j == n) {
			lenans = strlen(a);//答案字符串的长度
			break;
		}
		len[strlen(a)]++;

	}

	int cnt = 0;
	for(int j = 0; j < lenans; j++) {
		cnt += len[j];
	}
	int Min = cnt + cnt/k * 5 + 1;

	cnt = -1;
	for(int j = 0; j <= lenans; j++) {
		cnt += len[j];
	}
	int Max = cnt + cnt/k * 5 + 1;
	printf("%d %d\n", Min, Max);
	return 0;
}

/*
5 4
12
23
43
546
123
123

4 10



*/


您可能感兴趣的与本文相关的镜像

Yolo-v8.3

Yolo-v8.3

Yolo

YOLO(You Only Look Once)是一种流行的物体检测和图像分割模型,由华盛顿大学的Joseph Redmon 和Ali Farhadi 开发。 YOLO 于2015 年推出,因其高速和高精度而广受欢迎

<think> 题目链接:https://codeforces.com/problemset/problem/519/B 题目大意:给出n个数字,然后给出n-1个数字(第一组),再给出n-2个数字(第二组)。第一组是原数组去掉一个元素,第二组是第一组再去掉一个元素。求被去掉的两个元素(按顺序,即第一个被去掉的是第一个答案,第二个被去掉的是第二个答案)。 方法1:使用求和法 原数组的和为s0,第一组数组的和为s1,则第一个被去掉的数为 s0 - s1。 第二组数组的和为s2,则第二个被去掉的数为 s1 - s2。 方法2:使用排序或哈希表(统计频率) 原数组为a,第一组数组为b,第二组数组为c。 第一个被去掉的元素:在a中出现但不在b中出现的元素,或者在a中比b中多出现一次的元素。 第二个被去掉的元素:在b中出现但不在c中出现的元素,或者在b中比c中多出现一次的元素。 考虑到可能有重复元素,所以使用统计频率的方法更可靠。 具体步骤: 1. 读入原数组a(长度为n),第一组数组b(长度为n-1),第二组数组c(长度为n-2)。 2. 分别统计a、b、c中每个元素的出现频率。 3. 第一个答案:遍历a的元素,找到在a中出现的次数比在b中多一次的元素(或者遍历b的元素,但注意a中可能有b没有的元素,所以遍历a更安全)。 具体:对于a中的每个元素x,如果a中x的频率比b中x的频率大1,则x就是第一个被去掉的。 但注意:因为b中可能没有x,所以当b中不存在x时,b中x的频率为0,此时a中x的频率应该是1(比0大1),所以成立。 4. 第二个答案:同理,遍历b的元素,找到在b中出现的次数比在c中多一次的元素。 但是需要注意:同一个元素可能在数组中出现多次,所以不能只用一个标记,必须统计频率。 另一种方法:由于题目保证答案唯一,我们可以用以下方法: 第一个答案 = 在数组a中出现但在数组b中少出现一次的元素(即a中比b中多一个的元素)。 第二个答案 = 在数组b中出现但在数组c中少出现一次的元素。 实现: 使用map来统计每个数组的元素频率。 但是注意:在统计第二个答案时,我们要在b中找比c中多一次的元素,而b中已经包含第一个答案,所以第一个答案在b中可能比a中少一次,但我们并不关心,因为第二个答案与第一个答案不同。 步骤: 1. 读入n,然后读入三个数组。 2. 分别用三个map统计a, b, c中每个元素的频率。 3. 遍历a中的每个元素,对于每个元素x,如果freq_a[x] != freq_b[x](实际上应该大1),则第一个答案就是x,并跳出(但注意可能有多个?题目保证唯一,所以找到一个即可?但是因为同一个元素出现多次,我们只需找到一个元素在a中频率比b中多1即可,但这样的元素只有一个,因为只去掉一个元素,所以整个数组a中只有一个元素会多一次。但实际上,如果有重复元素,那么可能有多个元素在a中的频率比b中多1?但是仔细分析:只去掉一个元素,所以整个数组a和b之间,只有被去掉的那个元素在a中的频率比b中多1,其他元素都相同。所以我们可以遍历a,找到第一个满足freq_a[x] > freq_b[x]的元素,然后输出并跳出?但是有可能这个元素在b中不存在,所以用freq_b[x]可能为0。 具体:我们可以这样: for (auto x: a) { if (freq_a[x] - freq_b[x] == 1) { first = x; break; } } 但是注意:在遍历时,同一个x可能出现多次,所以不能一找到就break,因为可能后面还有?不对,因为同一个x,我们通过频率比较,如果这个x在a中出现了k次,那么在b中出现了k-1次,那么当我们遍历到x时,就会满足条件。但是这样会多次检测到同一个x,所以我们可以记录下这个x,然后跳出循环?但是这样会重复记录同一个x多次。因此,我们可以遍历map,而不是遍历数组a。 改进:遍历频率映射: for (auto it : freq_a) { int x = it.first; if (it.second - freq_b[x] == 1) { first = x; break; } } 但是这里要注意:freq_b中可能没有x,所以我们需要检查x是否在freq_b中?或者我们初始化freq_b时,对于a中所有元素都初始化了?没有。所以我们可以这样:使用map的find方法,或者直接访问freq_b[x],如果x不在freq_b中,则返回0(因为我们使用map,默认值0)。 同样,第二个答案:遍历freq_b,找freq_b[x] - freq_c[x] == 1的元素。 但是注意:第一个答案也可能在b中出现(在c中不出现)吗?第二个答案只与b和c有关,所以这样找没有问题。 但是:第一个答案被去掉后,在b中就不存在了?不对,b是去掉第一个答案后的数组,所以第一个答案在b中出现的次数应该比a中少1(如果a中出现了多次,那么b中只少一次)。所以我们的方法正确。 但是:如果a中有重复元素,比如a=[2,2,3],b=[2,3],那么第一个被去掉的是2。那么freq_a[2]=2,freq_b[2]=1,所以2满足条件。而其他元素(3)在a和b中频率相等。 所以我们可以使用频率差的方法。 步骤: 1. 读入n,然后读入数组a(n个数),数组b(n-1个数),数组c(n-2个数)。 2. 定义三个map:freq_a, freq_b, freq_c。 3. 统计a中每个元素的频率,b中每个元素的频率,c中每个元素的频率。 4. 遍历freq_a,找到第一个满足 freq_a[x] - (freq_b.count(x)?freq_b[x]:0) == 1 的x,作为第一个答案。 5. 遍历freq_b,找到第一个满足 freq_b[x] - (freq_c.count(x)?freq_c[x]:0) == 1 的x,作为第二个答案。 但是注意:第一个答案可能有多个元素满足条件吗?题目保证唯一,所以只有一个元素会被去掉,所以只有一个元素满足这个条件。因此,我们找到第一个满足条件的x即可(但map遍历是随机的,所以最好直接遍历,然后输出找到的第一个,因为只有一个)。 但是,我们也可以不用map遍历,而是遍历数组a(但数组a有重复,所以可能重复找到同一个元素多次)。所以还是遍历map比较好。 但是注意:题目要求按顺序输出:先输出的第一个被去掉的,再输出第二个被去掉的。 所以,我们也可以这样: 第一个答案:遍历a,直到找到一个元素x,使得freq_a[x] > freq_b[x](并且我们每找到一个,就在freq_b[x]上加1?这样不行)。所以还是用map统计后直接查找。 代码实现: 注意:由于n最大10^5,所以用map统计不会超时(O(n log n))。 另外:也可以使用unordered_map(平均O(n))。 代码: 方法1:使用map(或unordered_map)统计频率。 但是:题目要求按顺序输出两个答案,所以先输出第一个被去掉的,再输出第二个。 步骤: 1. 读入数组a,b,c。 2. 统计频率: map<int, int> fa, fb, fc; for (int i=0; i<n; i++) fa[a[i]]++; for (int i=0; i<n-1; i++) fb[b[i]]++; for (int i=0; i<n-2; i++) fc[c[i]]++; 3. 然后: int first = 0, second = 0; for (auto it : fa) { int num = it.first; if (it.second != fb[num]) { // 因为只少一个,所以一定是fa[num] == fb[num] + 1 first = num; break; // 因为只有一个,所以找到就可以退出 } } for (auto it : fb) { int num = it.first; if (it.second != fc[num]) { second = num; break; } } 4. 输出 first 和 second。 但是,注意:在第一个循环中,我们遍历fa,然后比较fa[num]和fb[num](如果num不在fb中,fb[num]默认0)。但是当fa[num]不等于fb[num]时,我们直接取num作为第一个答案并跳出。因为只少一个元素,所以这样的元素只有一个。 但是:在第二个循环中,同样遍历fb,然后比较fb[num]和fc[num](如果num不在fc中,则fc[num]为0)。 但是:有没有可能第一个循环中,有多个元素满足fa[num]!=fb[num]?题目保证答案唯一,所以只有一个元素被去掉,所以只有一个元素满足fa[num]!=fb[num](即fa[num]比fb[num]大1,而其他都相等)。 但是,我们这样写可能会遇到问题:如果一个元素在a中不存在,但在fa中不会出现(因为我们遍历fa,所以不会出现这种情况)。所以正确。 但是:如果第一个答案在a中只出现一次,那么fb中这个元素就不存在(即fb[num]为0),此时fa[num]=1,fb[num]=0,满足不等。 所以,这个方法正确。 但是,有一个小问题:遍历map时,我们不知道顺序,但题目不要求顺序,只要输出那个被去掉的元素即可(因为答案唯一),所以任意顺序遍历map都可以。 但是,我们也可以不用map,而用数组求和法(更简单,且O(n)): long long s1 = 0, s2 = 0, s3 = 0; for (int i=0; i<n; i++) s1 += a[i]; for (int i=0; i<n-1; i++) s2 += b[i]; for (int i=0; i<n-2; i++) s3 += c[i]; int first = s1 - s2; int second = s2 - s3; 求和法更简单,且效率高(O(n)),但要注意数据范围:n最大10^5,元素最大10^9,那么s1最大10^14,所以用long long不会溢出(long long最大9e18)。 所以,推荐使用求和法。 但是,求和法有一个问题:如果数组中有重复元素,并且被去掉的元素是重复的,会不会影响?不会,因为求和法就是计算总和,去掉一个元素,那么两个数组的差就是这个元素。 所以,求和法完全正确。 因此,我们可以写两种方法,但这里推荐求和法(更简单高效)。 代码(求和法): #include <iostream> using namespace std; int main() { int n; cin >> n; long long a_sum = 0, b_sum = 0, c_sum = 0; int x; for (int i = 0; i < n; i++) { cin >> x; a_sum += x; } for (int i = 0; i < n-1; i++) { cin >> x; b_sum += x; } for (int i = 0; i < n-2; i++) { cin >> x; c_sum += x; } long long first = a_sum - b_sum; long long second = b_sum - c_sum; cout << first << endl; cout << second << endl; return 0; } 但是,题目要求输出两个答案,第一个答案和第二个答案。 但是,有没有可能多个不同的元素被去掉,但是和相同?题目没有说元素互不相同,所以有可能出现两个不同的元素和相同吗?题目要求去掉两个元素(但这两个元素可能相同),但是注意:在第一个数组中,去掉一个元素后得到第二个数组,再去掉一个元素得到第三个数组。所以两个被去掉的元素可能是相同的。 但是,用求和法:第一个答案 = a_sum - b_sum,第二个答案 = b_sum - c_sum。 如果两个被去掉的元素相同,比如a_sum - b_sum = X,b_sum - c_sum = X,那么输出两个X。 所以,求和法完全正确。 但是,题目中是否有说明元素互不相同?没有,所以可能重复。 因此,我们使用求和法。 但是,注意:题目要求输入输出格式,以及多个测试用例?看题目描述:输入第一行是n,然后第二行是n个整数(原数组),第三行是n-1个整数(第一组),第四行是n-2个整数(第二组)。 所以,我们只需要读入一次。 但是,题目中可能有多个测试用例?不,题目描述:The first line contains integer n (3≤n≤10^5) — the initial length of the array. 所以只有一个测试用例。 但是,我们再看题目:Input中第一行是n,所以代码按单组输入。 所以,最终代码: 注意:使用long long,因为元素最大10^9,n最大10^5,总和最大10^14。 代码: </think> 对于 Codeforces 519B 问题,我将提供两种优化解法:**求和法**(推荐)和**频率统计法**。原始问题需要找出两次删除操作中被移除的元素。 ### 解法一:求和法(O(n) 时间复杂度) 这是最优解法,利用数组和的差值直接计算被移除的元素: ```cpp #include <iostream> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; long long a_sum = 0, b_sum = 0, c_sum = 0; int x; // 读取原始数组并求和 for (int i = 0; i < n; i++) { cin >> x; a_sum += x; } // 读取第一次删除后的数组并求和 for (int i = 0; i < n - 1; i++) { cin >> x; b_sum += x; } // 读取第二次删除后的数组并求和 for (int i = 0; i < n - 2; i++) { cin >> x; c_sum += x; } // 计算被移除的元素 long long first_removed = a_sum - b_sum; long long second_removed = b_sum - c_sum; cout << first_removed << "\n"; cout << second_removed << "\n"; return 0; } ``` #### 代码解释: 1. **输入处理**: - 读取数组大小 `n` - 使用 `long long` 防止总和溢出(元素值 ≤10⁹,n≤10⁵,总和最大 10¹⁴) 2. **求和计算**: - `a_sum`:原始数组总和 - `b_sum`:第一次删除后数组(n-1 个元素)总和 - `c_sum`:第二次删除后数组(n-2 个元素)总和 3. **差值计算**: - `first_removed = a_sum - b_sum`:第一个被删除的元素 - `second_removed = b_sum - c_sum`:第二个被删除的元素 4. **时间复杂度**:O(n),仅需三次线性遍历 ### 解法二:频率统计法(O(n log n) 时间复杂度) 使用哈希表统计元素频率,适合元素值范围大的情况: ```cpp #include <iostream> #include <vector> #include <unordered_map> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; vector<int> a(n), b(n-1), c(n-2); unordered_map<int, int> freq_a, freq_b, freq_c; // 读取并统计原始数组频率 for (int i = 0; i < n; i++) { cin >> a[i]; freq_a[a[i]]++; } // 读取并统计第一次删除后数组频率 for (int i = 0; i < n - 1; i++) { cin >> b[i]; freq_b[b[i]]++; } // 读取并统计第二次删除后数组频率 for (int i = 0; i < n - 2; i++) { cin >> c[i]; freq_c[c[i]]++; } // 查找第一个被删除的元素 int first_removed = 0; for (int num : a) { if (freq_a[num] != freq_b[num]) { first_removed = num; break; } } // 查找第二个被删除的元素 int second_removed = 0; for (int num : b) { if (freq_b[num] != freq_c[num]) { second_removed = num; break; } } cout << first_removed << "\n"; cout << second_removed << "\n"; return 0; } ``` #### 代码解释: 1. **数据结构**: - 使用 `unordered_map` 存储元素频率(平均 O(1) 操作) - `vector` 存储输入数组 2. **频率统计**: - `freq_a`:原始数组频率 - `freq_b`:第一次删除后频率 - `freq_c`:第二次删除后频率 3. **查找被删元素**: - 第一个元素:在 `a` 中频率比 `b` 大 1 的元素 - 第二个元素:在 `b` 中频率比 `c` 大 1 的元素 4. **时间复杂度**:O(n log n)(哈希表操作均摊 O(1)) ### 两种解法对比 | 特性 | 求和法 | 频率统计法 | |--------------|---------------------------|--------------------------| | 时间复杂度 | O(n) | O(n)(均摊) | | 空间复杂度 | O(1) | O(n) | | 适用场景 | 推荐通用解法 | 元素范围极大时更稳定 | | 优势 | 代码简洁,内存占用少 | 不依赖数值计算 | | 注意事项 | 总和可能溢出(用long long)| 哈希冲突可能影响性能 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值