P3612 [USACO17JAN] Secret Cow Code S

题目描述

The cows are experimenting with secret codes, and have devised a method for creating an infinite-length string to be used as part of one of their codes.

Given a string s, let F(s) be s followed by s "rotated" one character to the right (in a right rotation, the last character of s rotates around and becomes the new first character). Given an initial string s, the cows build their infinite-length code string by repeatedly applying F; each step therefore doubles the length of the current string.

Given the initial string and an index N, please help the cows compute the character at the Nth position within the infinite code string.

输入格式

The input consists of a single line containing a string followed by N. The string consists of at most 30 uppercase characters, and N ≤ 10^{18}.

Note that N may be too large to fit into a standard 32-bit integer, so you may want to use a 64-bit integer type (e.g., a "long long" in C/C++).

输出格式

Please output the Nth character of the infinite code built from the initial string. The first character is N = 1.

题意翻译

奶牛正在试验秘密代码,并设计了一种方法来创建一个无限长的字符串作为其代码的一部分使用。

给定一个字符串,让后面的字符旋转一次(每一次正确的旋转,最后一个字符都会成为新的第一个字符)。也就是说,给定一个初始字符串,之后的每一步都会增加当前字符串的长度。

给定初始字符串和索引,请帮助奶牛计算无限字符串中位置 N 的字符。

第一行输入一个字符串。该字符串包含最多 30 个大写字母,数据保证 N ≤ 10^{18}

第二行输入 N。请注意,数据可能很大,放进一个标准的 32 位整数可能不够,所以你可能要使用一个 64 位的整数类型(例如,在 C/C++ 中是 long long)。

请输出从初始字符串生成的无限字符串中的位置的字符。第一个字符是 N = 1。

输入输出样例

输入

COW 8

输出

C

说明/提示

In this example, the initial string COW expands as follows:

COW -> COWWCO -> COWWCOOCOWWC

12345678

思路

1.面对 10^{18}这样量级的数字,我们无法使用模拟来做,只能找数字间的关系,将要求的 n “映射”到原来的字符串中,从而输出指定字符

2.我们可以发现,每一次增长增长的部分的第一位跟原部分的最后一位相同,增长部分的第二位到最后一位跟原部分的第一位到倒数第二位相同,COW--->CO W W CO--->COWWC O O COWWC因此手动模拟一下可以发现它们的规律(见文末图)

错误代码

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
string s;
int n, tmp, m;
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> s >> n;
	m = s.size();	//出错的关键
	while (m < n)	m *= 2;	//出错的关键
	tmp = n;
	while (tmp > s.size()) {
		m /= 2;
		if (tmp == m + 1)	tmp -= 1;
		else tmp = tmp - m - 1;
	}
	cout << s[tmp-1];
	return 0;
}

错误点

整体代码的思路都是正确的,就是限定m的时候出错了(代码中写了注释的两行),正确的做法是把m放到while循环中动态决定,而我第一次做的时候就在外面限定好了,每次循环除以2。因为:有的时候“映射”不一定是相邻的互相“映射”,甚至可以一次性“映射”到最初的字符串,但除以二意味着“映射”到相邻的子列,故错误。

AC代码

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
string s;
int n, tmp, m;
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> s >> n;
	tmp = n;
	while (tmp > s.size()) {
		m = s.size();
		while (m < tmp)	m *= 2;
		m /= 2;
		if (tmp == m + 1)	tmp -= 1;
		else tmp = tmp - m - 1;
	}
	cout << s[tmp-1];
	return 0;
}

草稿图

 

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Achilles0705.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值