A n是奇數,f(n)一定是奇數;n是偶數,f(n)一定是2;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
int t;
ll n,k;
bool pr[N];
int main()
{
cin>>t;
while(t--)
{
cin>>n>>k;
if((n&1)&&k)
{
bool flag=1;
for(int i=3;i<=n/i;i++)
if(n%i==0)
{
flag=0;
n+=i;
k--;
break;
}
if(flag)
{
n+=n;k--;
}
}
cout<<n+k*2<<endl;
}
return 0;
}
B 選擇一堆下标,第i個下标可以被第i+1個下标整除,且該子序列是單增。
先預處理出來每個數的因子就好。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int t,n,a[N];
vector<int> ve[N];//ve[i]儲存能被i整除的數
int f[N];
void init()
{
ll cnt=0;
for(int i=2;i<N;i++)
{
ve[i].push_back(1);
for(int j=2;j <= i/j;j++)
{
if((i%j)==0)
{
ve[i].push_back(j);
if(i/j!=j) ve[i].push_back(i/j);
}
}
}
}
int main()
{
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(f,0,sizeof f);
for(int i=1;i<=n;i++) scanf("%d",a+i);
int ans=1;
f[1]=1;
for(int i=2;i<=n;i++)
{
f[i]=1;
for(int j=0;j<ve[i].size();j++)
if(a[i]>a[ve[i][j]])
f[i]=max(f[i],f[ve[i][j]]+1);
ans=max(ans,f[i]);
}
printf("%d\n",ans);
}
return 0;
}
C 資料這麼大肯定要分解質因數來求了。
假如n個數都含有質因子p,n個數的次幂分别是:m1,m2,m3…mn(已經從小到大排好序)。先求lcm,就是任意兩個數mi和mj( i!=j )的最大值,那麼會得到1個m2,2個m3…,再對他們求gcd,即這 (n-1)*n/2個數中最小值:m2,(n個數中次幂第二小);
如果隻有n-1個數含最因子p,那麼令m1=0;那麼lcm還會得到1個m2,2個m3…,gcd還是取m2,(即n-1個數中次幂最小值);
當少于n-1個數含有質因子p,m2=0,最終求得的次幂是0,忽略不計。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
int t,n,a[N];
int res[N][2];//res[i][0]:i的次幂最小值,res[i][1]次幂第二小
vector<int> ve[N];
int num[N];
int main()
{
scanf("%d",&n);
int m=0;
for(int i=1;i<=n;i++) scanf("%d",a+i),m=max(m,a[i]);
for(int i=1;i<=n;i++)
{
int t=a[i];
map<int,int> mp;
for(int j=2;j<=t/j;j++)
{
int cnt=0;
while(t%j==0)
{
t/=j;
cnt++;
}
if(cnt)
{
if(num[j]==0) res[j][0]=cnt;
else if(num[j]==1)
{
if(cnt>=res[j][0]) res[j][1]=cnt;
else
{
res[j][1]=res[j][0];
res[j][0]=cnt;
}
}
else if(cnt<res[j][0])
{
res[j][1]=res[j][0];
res[j][0]=cnt;
}
else if(cnt<res[j][1])
{
res[j][1]=cnt;
}
num[j]++;
}
}
if(t>1)
{
int cnt=1;
if(num[t]==0) res[t][0]=cnt;
else if(num[t]==1)
{
if(cnt>=res[t][0]) res[t][1]=cnt;
else
{
res[t][1]=res[t][0];
res[t][0]=cnt;
}
}
else if(cnt<res[t][0])
{
res[t][1]=res[t][0];
res[t][0]=cnt;
}
else if(cnt<res[t][1])
{
res[t][1]=cnt;
}
num[t]++;
}
}
ll ans=1;//答案沒有爆ll
for(int i=2;i<=m;i++)
{
if(num[i]==n)
{
int t=res[i][1];
while(t--)//用pow函數就會錯,貌似int型會重載
ans=ans*i;
}
else if(num[i]==n-1)
{
int t=res[i][0];
while(t--)
ans=ans*i;
}
}
printf("%lld",ans);
return 0;
}
用優先隊列會短一些
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
int t,n,a[N];
int res[N][2];
vector<int> ve[N];
int num[N];
priority_queue<int,vector<int>,greater<int> > q[N];
int main()
{
scanf("%d",&n);
int m=0;
for(int i=1;i<=n;i++) scanf("%d",a+i),m=max(m,a[i]);
for(int i=1;i<=n;i++)
{
int t=a[i];
for(int j=2;j<=t/j;j++)
{
int cnt=0;
while(t%j==0)
{
t/=j;
cnt++;
}
if(cnt)
{
num[j]++;
q[j].push(cnt);
}
}
if(t>1)
{
q[t].push(1);
num[t]++;
}
}
ll ans=1;
for(int i=2;i<=m;i++)
{
if(num[i]==n)
{
q[i].pop();
int t=q[i].top();
while(t--)
ans=ans*i;
}
else if(num[i]==n-1)
{
int t=q[i].top();
while(t--)
ans=ans*i;
}
}
printf("%lld",ans);
return 0;
}
補:
D 已知有n個數,每次操作可以選擇一個區間使得區間内中位數替換區間所有數,問進行若幹次操作是否可以将n個數都變為k。
首先一定要有k才可以操作成功;
① 操作兩個數時,隻有一個數等k一個數大于等于k或者兩個數都是k才能使得兩個數變為k;
② 操作三個數時隻有k是第二小時才能使三個數都變為k。
如果産生了長度大于等于兩個的連續k,那麼将連續區間向左或右擴充一個數,不論這個數是幾都可以把它變為k。
是以就要判斷是否能得到連續k了:
滿足①和②直接就可以了,那麼其他情況呢
如果兩個數都比k大的話,那麼操作之後兩個數一定相等且比k大(不用管具體是幾,隻用知道比k大就可以了),然後繼續向兩邊每次擴充一個數,就會得到一段連續區間一定比k大,直到擴充到k(k存在的情況下)就該操作k和這個區間與k相鄰的一個端點了,已知已經把這個端點變為比k大了,那麼滿足①,再以這兩個數為起點繼續擴充就可以了。
那麼如果是兩個比k大的數相隔一個數呢,不滿足上面的情況。但是操作這三個數一定可以将這三個數變得都比k大(還是不用管具體值),繼續上面的思路就一定可解。
綜上:當連續兩個數中大于等于k的個數大于等于2或者連續三個數中大于等于k的個數大于等于2,二者有一就可解。
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,t,k,a[N],b[N];
int main()
{
cin>>t;
while(t--)
{
cin>>n>>k;
bool flag1=0,flag2=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]==k) flag1=1;
if(a[i]>=k) b[i]=1;
else b[i]=0;
}
for(int i=1;i<n;i++)
if(b[i]+b[i+1]>=2)
flag2=1;
for(int i=1;i<n-1;i++)
if(b[i]+b[i+1]+b[i+2]>=2)
flag2=1;
if(flag1&&(flag2||n==1))
puts("yes");
else puts("no");
}
return 0;
}