1096.連続する要因(20)
正の整数Nのすべての要素の中で、いくつかの連続した数が存在する場合があります。たとえば、630は3×5×6×7として因数分解できます。5、6、および7は3つの連続した数値です。ここで任意の正のNが与えられると、連続する因子の最大数を見つけ、連続する因子の最小のシーケンスをリストすることになります。
入力仕様:
各入力ファイルには、整数N(1 <N <2 ^ 31)を与える1つのテストケースが含まれています。
出力仕様:
各テストケースについて、最初の行に連続する因子の最大数を出力します。次に、2行目に、連続する因子の最小シーケンスをの形式で出力しますfactor[1]*factor[2]*...*factor[k]
。ここで、因子は昇順でリストされており、1は含まれていません。
入力例
630
出力例
3
5*6*7
結局のところ、これは20点の質問です。主題は非常に理解しやすく、直接列挙することができます。暴力的に聞こえるかもしれませんが、このシーケンスは一般的に非常に短いため、中央の多くの数値はそれ自体の要因ではないことは言うまでもありません。
それを書いた後、ダブルポインターメソッドを使用して実装しようとしました。基本的には時間の複雑さは低くなると思いましたが、必要なシーケンスの条件が厳しすぎるため、これらの非階乗数のポインターで多くの時間が無駄になっています。どうぞ。これは私に別の教訓を与えます:アルゴリズムを選択する前に、このアルゴリズムが処理されるデータと必要な結果に適合するかどうか真剣に考える必要があります。
コードは次のとおりです。
#include <bits/stdc++.h>
using namespace std;
int main(){
freopen("input.md","r",stdin);
long long n;
scanf("%lld",&n);
int sqr=n>4?sqrt(n):n;
int left=2,right=1,pro=1,maxlen=0;//双指针大法
pair<int,int> ans;
bool isprime=true;
while(right<=sqr){
pro*=(right+1);//试探一下
if(n%pro==0){//ojbk,直接右移
isprime=false;
right++;
}
else{//不ok,先检查当前长度是否更优并保存结果,然后右指针右移一位,
if(right-left+1>maxlen){
maxlen=right-left+1;
ans={left,right};
}
right++;
//然后左指针开始右移,不断缩短当前序列看是否符合要求
while(left<=right && n%pro!=0){
pro=pro/left;
left++;
}
}
}
if(isprime)
printf("1\n%d",n);
else{
printf("%d\n",maxlen);
for(int i=ans.first;i<=ans.second;i++){
if(i!=ans.first) printf("*");
printf("%d",i);
}
}
return 0;
}
//柳神的代码,直接枚举
// long int num, temp;
// int main(){
// freopen("input.md","r",stdin);
// cin >> num;
// int first = 0, len = 0, maxn = sqrt(num);
// for (int i = 2; i <= maxn; i++){
// int j; temp = 1;
// for (j = i; j <= maxn; j++){
// temp *= j;
// if (num % temp != 0) break;
// }
// if (j - i > len){
// len = j - i;
// first = i;
// }
// }
// if (first == 0) cout << 1 << endl << num;
// else {
// cout << len << endl;
// for (int i = 0; i < len; i++){
// cout << first + i;
// if (i != len - 1) cout << '*';
// }
// }
// return 0;
// }
2ポインターメソッドの送信結果は次のとおりです。
直接列挙の送信結果は次のとおりです。