PAT.1096 Consecutive Factors
看题干的意思是给出一个数n,要你寻找在所有可能的因数分解序列上上最长的连续因数子序列,输出这个长度并输出最小的子序列。
说实话这个最小我一开始没怎么看明白,因为如果说最小是左界最小,那明显样例的输出应该是1*2*3
而不是5*6*7
,但如果说这个最小指的是size最小,那输出应该是3
,也不是5*6*7
,于是我陷入了疑惑…
首先想到的做法是在1-N的范围上做滑动窗口,还就那个处理连续子序列相关问题的经典思路,先是按照左界最小的做法提交了一次(当然不可能是对的,因为样例都过不了)。
一些尝试
在左界最小没能通过的情况下,在左界最小的基础上不考虑因数分解中包含1的情况,即从2开始做滑动窗口,拿到了15/20,最后一个测试点超时(想想也是,毕竟1e9的数据摆在那里)。
那么看来题干的最小很可能是最小左界,同时不包含1的情况。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,l = 2,r = 2,maxSize = 0;
deque<ll> res;
deque<ll> window;
int main(){
cin>>n;
while(r <= n){
if(n % r == 0){
window.push_back(r);
if(r - l + 1 > maxSize){
maxSize = r - l + 1;
res = window;
}
r++;
}else{
if(!window.empty()) window.pop_front();
l++;
r = max(l,r);
}
}
cout<<maxSize<<endl;
while(!res.empty()){
cout<<res.front();
res.pop_front();
if(res.size() > 0) cout<<"*";
}
}
题解
还就那个恶堕然后使用枚举。
首先考虑枚举什么,因为连乘增长很快,只要大概十几连乘就能超过1e9,所以我们可以考虑枚举子序列的长度。同时显然,只要两个大于sqrt(n)
的数相乘就会大于n,所以我们枚举子序列中的数的时候只需要考虑小于sqrt(n)
的数(这里有一点需要注意,就是序列刚好跨过开根的情况,比如6=2*3
,所以实际上我们应该枚举的范围是2 ~ sqrt(n) + 1
)
理清思路后我们只要从枚举左界的同时枚举子序列的长度即可,对于PAT的数据,考虑到开根的情况,子序列长度枚举到6、7就能过全部测试点了。
特别需要注意的是:
- 这个方法对质数无可奈何,当n为质数时会得到最大子序列长度为0,所以我们需要进行特判,在这种情况下直接输出
1\nN
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,carry;
int r,maxSize;
vector<int> window;
vector<int> res;
int main(){
cin>>n;
r = sqrt(n) + 1;
for(int i = 2 ; i <= r ; ++i){
carry = 1;
window.clear();
for(int len = 1 ; len <= 6 ; ++len){
carry *= i + len - 1;
if(n % carry == 0){
window.push_back(i + len - 1);
if(window.size() > maxSize){
maxSize = window.size();
res = window;
}
}else break;
}
}
if(maxSize == 0) cout<<1<<endl<<n;
else{
cout<<maxSize<<endl;
for(int i = 0 ; i < maxSize ; ++i){
cout<<res[i];
if(i != maxSize - 1) cout<<"*";
}
}
}