L1-006 连续因子 (20 point(s))

  • 这题跟前面相比难度骤增,可能因为我不知道怎么分解因数,之前似乎也没写过这种分解因数的题目,质因数可能有,但这题不是质因数,所以没AC麻了。

    后面用别人的测试数据才发现,自己从大到小遍历,会存在因数未能完全分解,比如输入 1260 的话,以12分代码思路只能够得到 3 20 21 的因数。但实际 20 应该进一步分解 得到 4 和 5 。

    参考理解

  • 看了下别人的代码发现原本思路的错误,理解错题目的描述了。

    “求出最长连续因子的个数,并输出最小的连续因子序列” 最长的因子个数没问题,但是最小连续因子错了。

    2 3
    3 4
    3 4 5
    4 5 6
    

    比如有一堆因子序列,可以看到最长因子个数是 3 ,而最小连续因子呢,之前以为答案是 2 3 ,是以全部连续因子序列中以最小的首元素为依据。

    但实际要求的最小连续因子序列是 3 4 5 。意味是在最长连续因子序列中,找到首元素最小的序列输出。

  • 试了试从小到大遍历的问题,发现这样的思路还是存在问题。

    image

    虽然得到了全部因子的序列,但是截断连续因子可能前面是连续,后面也是连续的因子序列,但因为我们只处理了一次,所以后面的就没有处理。比如第一个全部因子序列有 2 3 5 6 7 ,前面 2 3 是连续,后面 5 6 7 也是连续因子。而后面就没有处理所以就被忽略。

  • 思考这段代码跟我们原本思路的差异。之前自己写的时候,想先获取 N 的全部因子,然后提取中间连续的因子部分,但就像上面所说,得到的因子不一定是最简的,不能得到正确的结果。

    for (int i = 2; i <= sqrt(N); ++i) {
    	int tmp = N, j = i, count = 0;
    	while (tmp % j == 0) 
    		tmp /= j++, count++;
    	if (count > maxcount)
    		maxcount = count, start = i;
    }
    

    而别人正确的代码的思路,没有获取 N 全部的因子,只截取其中一部分连续的因子序列。

    所以可以看到,当下面这部分代码对 j 判断,不满足 tmp % j == 0 就退出循环,并记录这个序列初始元素 i 和长度 count 。

    参考代码

  • 试了下别人的代码后,还有一个地方有疑惑,为什么要判断因子的存在而输出连续序列,如果没有因子就直接输出 N 。

    如果我们改变判断的范围,比如原本是遍历到 sqrt(N) 扩大到 N 是不是类似的。

    看了别人的文章知道,原来 N 可能是素数,而素数的因子仅仅包含 1 和其本身 N 。所以判断范围仅仅在 sqrt(N) 的话,就不能够遍历到 N 取其作为因子。

    而我们不可能循环遍历到 N,因为 sqrt(N) 后面的数都不会作为 N 的因子。同时如果把范围扩大到 N 还会超时。所以直接对这个特殊情况进行特判

    测试点六

  • 从这题其实还应该学到一个思路。从别人的代码可以看到没有获取全部的序列,只获取了连续的序列。

    那这样获取会不会有问题。比如下一个因子不是属于因子怎么办。从别人的代码可以看到,只需要处理的时候再判断一下就可以了。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int maxCnt = 0, N, start; 
	cin >> N;
	
	for(int i = 2; i <= sqrt(N); i++){
		int tmp = N, cnt = 0;
		
		// 找连续因子序列 
		for(int j = i; tmp % j == 0; j++){
			tmp /= j; cnt++;
		}
		// 更长则更新序列 
		if(maxCnt < cnt){
			maxCnt = cnt; 
			start = i;
		}
	}
	
	if(maxCnt){
		cout << maxCnt << endl;
		for(int i = start; i < start + maxCnt; i++)
			cout << (i == start ? "" : "*") << i;
	}
	else
		cout << 1 << endl << N;
} 
// 12 points
#include <bits/stdc++.h>
#include <vector>
using namespace std;

int N, maxn = 0;
map<int, vector<int>> minSeq;

void process(vector<int> f){
	// 升序
	sort(begin(f), end(f)); 
	
	// 保存前置因子 
	for(int i = 0; i < f.size(); i++){
		vector<int> ans;
		int deal = false;
		ans.push_back(f[i]); 
		
		// 差值为 1 开始保存 直到差值不为 1 
		for(int j = i; f[j+1] - f[j] == 1 && j + 1 < f.size(); j++){
			deal = true;
			ans.push_back(f[j+1]); 
		}
		
		// 如果处理了则更新
		if(deal == true){
			if(maxn < ans.size()) 
				maxn = ans.size();
				
			// 如果序列首元素相等且长度大于原序列才更新 
			if(ans.size() > minSeq[ans[0]].size())
				minSeq[ans[0]] = ans;
		} 
	}
}

int main(){
	cin >> N;
	
	// 从大的因子开始找 
	for(int i = N; i >= 2; i--){
		int n = N, j = i;
		vector<int> factor;
		
		for(int j = i; j >= 2 && n != 1; j--){
			if(n % j == 0){
				factor.push_back(j);
				n /= j;	
			} 
		}
		
		// N 能够被整除到 1 处理因子 
		if(n == 1){
			//for(auto f: factor) cout << " " << f;
			//cout << endl;
			process(factor);
		}
	} 
	
	for(auto m: minSeq){
		for(auto v: m.second)
			cout << " " << v;
		cout << endl;
	}
	
	int first = 0;
	cout << maxn << endl;
	auto m = begin(minSeq);
	for(auto v: m->second)
		cout << (first++ ? "*" : "") << v;
} 

posted on 2021-09-29 13:36  Atl212  阅读(158)  评论(0)    收藏  举报

导航