A. Orac and Factors
題目描述:For n≥2, we will denote as f(n) the smallest positive divisor of n, except 1.定義f(n) 爲n的最小因子,除1以外。
Now, for two positive integers n and k, Orac asked you to add f(n) to n exactly k times (note that n will change after each operation, so f(n) may change too) and tell him the final value of n.
2.給定n和k,求n=n+f(n),一共k次。
分析:
隨便分析幾個數可得,n+f(n)會變成偶數。因此f(n)會變成2;
當n不爲偶數時,需要運用唯一分解定理,即確定其最小質因子,f(n)+n就會變成偶數。後面每一次相當於加上2;
//AC代碼;
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e6+55;
int prime[N];
bool p[N];
int cnt=0;
void deal()
{
for(int i=2;i<N;++i){
if(!p[i]){
prime[cnt++]=i;
}
for(int j=0;j<cnt&&i*prime[j]<N;++j){
p[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
int main()
{
int t,n,k;
ll ans;
deal();
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
if(n%2==0){
ans=n+2*k;
}else{
int x;
for(int i=0;i<cnt;++i){
if(n%prime[i]==0){
x=prime[i];
break;
}
}
ans=n+x+2*k-2;
}
printf("%lld\n",ans);
}
return 0;
}
B. Orac and Models
題目描述:
There are n models in the shop numbered from 1 to n, with sizes s1,s2,…,sns1,s2,…,sn.
Orac thinks that the obtained arrangement is beatiful, if for any two adjacent models with indices ij and ij+1(note that ij<ij+1, because Orac arranged them properly), ij+1 is divisible by ij and sij<sij+1.
給定一個數組,求數組下標成倍數的最長上升序列。
分析:
對於任意一個數,他有幾個因子,就可能有幾個上升序列。例如:20:1,2,4,5,10,都是他的因子。 (1≤n≤100000),根據數據範圍可以將每一個點記錄其最長上升序列,即dp[i]表示i之前的是i的因子的最長上升序列。
現在我們就需要解決如何將一個數的因子全部分解出來。我用了枚舉的方法
即1、2、3、、、sqrt(n)。
//狀態方程
if(num[i]>num[k]) dp[i]=max(dp[i],dp[k]+1);
//AC代碼;
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+55;
int num[N],dp[N];
int main()
{
int t,n,k;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&num[i]);
dp[i]=1; //初始化dp[i]爲1,每一個數本身都算一個;
}
for(int i=2;i<=n;++i){
int up=(int) sqrt(i); //尋找所有因子;
for(int j=1;j<=up;++j){
if(i%j==0){
k=i/j; //因子成對,即a*b=i,減少了時間複雜度,只需要找到sqrt(i);
if(num[i]>num[k]) dp[i]=max(dp[i],dp[k]+1);
if(num[i]>num[j]) dp[i]=max(dp[i],dp[j]+1);
}
}
}
int maxn=0;
for(int i=1;i<=n;++i)
maxn=max(maxn,dp[i]);
printf("%d\n",maxn);
}
return 0;
}
C. Orac and LCM
題目描述:
一串數{s1,s2,s3…},求這串數字中每對數的最小公倍數的最小公因子。For example, gcd({8,12})=4, gcd({12,18,6})=6, gcd({8,12})=4, gcd({12,18,6})=6 and lcm({4,6})=12, lcm({4,6})=12.
分析:
對於每對數(a,b)最小公倍數來說,包含這兩個數共有部分和每一個數的特有因子即: gcd(a,b)和a/gcd(a,b)、b/gcd(a,b);當n個數兩兩組合之後得到一組最小公倍數數集,再求這些數的最大公因子。相當於就是求這串數的共有部分相乘。由於是兩兩組合,所以只需要共有部分有n-1就行了。
例如:10 24 40 80 這4個數,分解開來就是 25、3222、5222、5222*2、5出現了3次,2出現了4次,4出現了3次,8出現了3次,但由於2、4可以屬於8,因此因子就可以有5、8兩個,也就是40;
//AC代碼;
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=2e5+55;
int p[N],prime[N];
bool pp[N];
void deal() //這兒用素數去分解它的因子,反正就是要找到所有公共因子
{
int cnt=0;
for(int i=2;i<N;++i){
if(!pp[i]){
prime[cnt++]=i;
}
for(int j=0;j<cnt&&prime[j]*i<N;++j){
pp[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
int main()
{
int n,x,y;
deal();
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",&x);
int j=0,k=0;
while(x>1){
while(x%prime[j]!=0){
++j;
if(prime[j]*prime[j]>x) {
k=1;
break;
}
}
if(k){
p[x]++;
break;
}
int cnt=1;
while(x%prime[j]==0){
cnt*=prime[j];
p[cnt]++; //每一個因子都要算進去,但後面以滿足條件的最大因子爲準。
x/=prime[j];
}
}
}
n--;
ll ans=1;
for(int i=N-22;i>1;--i){ //從最後面開始遍歷,大的將小的包含了。
if(p[i]>=n&&ans%i!=0) ans*=i;
}
printf("%lld\n",ans);
return 0;
}
剩餘的題也儘量補