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;
}