Codeforces 做题日记:面向结果最有用的一集E. Novice‘s Mistake

Codeforces Round 957 (Div. 3)E. Novice's Mistake

题目描述:

题目翻译过来其实很简单:

给你一个n,求方程a*n-b=nn...n(a-b个n)的所有解

额外说明一下这个nn...n(a-b个n)的意思,n可以是1~100的任何一个数,我们先把n重复a次,然后再在它的末尾删掉b个数,也就是说如果n是两位数或者100,那么最后的结果其实是2*n-b位数或者3*a-b位数,因为b每次只删一个,而重复a次时是将整个n重复

好,那么a的范围是1~10000,b的范围是1~min(10000,a*n),暴力遍历直呼不可战胜,但是我的脑子也根本想不到更好的方法(事实上答案上给的方法也是遍历了整个1~10000的a,居然还挺快,但是我用c++写的代码遍历1~10000过不了)

首先,是我想到的优化策略,(后来发现只能在n<10的情况下使用),仔细观察一下这个方程,我们可以发现,对两边都除以n,得到a-b/n=11....1,可见b一定是n的整数倍,这样就可以少遍历一些数了,其次,我们可以发现,a-b代表了两者结果的位数,那么当a*n-b的位数大于或小于a-b时,就可以直接跳过不用进行计算(事实上这样只是少做了几个计算,其实还是遍历了一遍,答案上的思路明显更好)使用之后依然没法通过(显然的,我在自己电脑上运行每个结果都要等个四五秒),但是,在我发现大部分结果都在3000以下的时候,我大胆的尝试将a和b的遍历范围缩小到1~3000,但还是超时了,此时a和b的遍历范围是1~3000,那么有没有办法来约束b的范围呢

那么我们来看看答案上的思路,仔细观察方程可以发现,a*n-b最多最多就是100*10000=1000000,七位数,而且实际肯定小于这个值,只有六位数,如果a*|n|-b大于六位数显然就不会有正确的输出,所以每次对于b的遍历只要从a*|n|-5~a*|n|就可以了!这样b的遍历次数大大减少,成功通过

(后来我试着把a从1~2600改回1~10000,发现又超时了,果然还得是邪道。。。)

(遍历范围变成1~2600还有一个问题,就是n=1时输出是错误的,因为n=1时a,b只要满足a-b=1都是正确的,所以只遍历到2600显然不对,所以我专门写了一个if用来输入n=1答案)

附代码:(相比于答案的简洁代码,我的只能说是臃肿而丑陋)

#include<iostream>
#include<string>
#include<vector>
#include<cmath>
using namespace std;



int main()
{
	int m = 0;
	cin >> m;
	while (m--)
	{
		int n = 0;
		cin >> n;
		vector<pair<int, int>> arr;
		if (n == 1)
		{
			cout << 9999 << endl;
			for (int i = 2; i <= 10000; i++)
			{
				cout << i << " " << i - 1 << endl;
			}
			continue;
		}
		else if (n < 10)
		{
			int count = 0;
			for (int a = 1; a < 2300; a++)
			{
				for (int b = max(1,a-5); b <a; b ++)
				{
					
						string c = to_string(n);
						string temp(a - b, c[0]);
						int string = stoi(temp);	
						if (string == a * n - b)
						{
							count++;
							pair<int, int> ans(a, b);
							arr.push_back(ans);
						}
				

				}
			}
			cout << count<<endl;
			for (int i = 0; i < arr.size(); i++)
			{
				cout << arr[i].first << " " << arr[i].second << endl;
			}
		}
		else if (n >= 10 && n < 100)
		{
			int count = 0;
			for (int a = 1; a < 2000; a++)
			{
				for (int b =max(1, 2*a-5); b < 2*a; b++)
				{

						string c = to_string(n);
						string string1(a * 2, ' ');
						for (int i = 0; i < a * 2; i += 2)
						{
							string1[i] = c[0];
						}
						for (int i = 1; i < a * 2; i += 2)
						{
							string1[i] = c[1];
						}
						string string2(string1.begin(), string1.begin() + a * 2 - b);
						int string3 = stoi(string2);
						if (string3 == a * n - b)
						{
							count++;
							pair<int, int> ans(a, b);
							arr.push_back(ans);
						}

				}
			}
			cout << count<<endl;
			for (int i = 0; i < arr.size(); i++)
			{
				cout << arr[i].first << " " << arr[i].second << endl;
			}
		}
		else if (n == 100)
		{
			cout << 0 << endl;
		}
	}
	return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值