A. Orac and Factors
题解
当 (n) 为偶数时, (n) 每次的最小因子(除 (1)以外)都是 (2)。
当 (n) 为奇数时,(n) 每次的最小因子(除 (1)以外)是奇数,当奇数加上奇数之后为偶数,则后面的 (k-1) 次都是(2)。
解决的思路:不论是不是奇数,先求解出最小的因子(除 (1)以外),再加上 ((k-1)*2) 。
代码
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
int main(){
int t;
scanf("%d",&t);
while(t--){
ll n,k;
scanf("%lld%lld",&n,&k);
ll m=sqrt(n),res=n,ret=n;
for(ll i=2;i<=m;++i){
if(n%i==0){
ret=i;
break;
}
}
res+=ret;
res+=(k-1)*2;
printf("%lld
",res);
}
return 0;
}
B. Orac and Models
题解
感觉代码很像筛法,对于任何一个数 (i) ,枚举它所有的最倍数,再根据条件 (a_i<a_j) 用于求解最大值。
注:初始化的坑很强大。
代码
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn];
int max(int x,int y){
return x>y?x:y;
}
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
b[i]=1;
scanf("%d",&a[i]);
}
int maxx=1;
for(int i=1;i<=n;++i){
for(int j=i*2;j<=n;j+=i){
if(a[j]>a[i]){
b[j]=max(b[j],b[i]+1);
maxx=max(maxx,b[j]);
}
}
}
printf("%d
",maxx);
}
return 0;
}
C. Orac and LCM
题解
求解 (gcd({lcm({ai,aj}) | i<j})) 最暴力的解法是 枚举所有的 (i) 和 (j) 来进行求解
for(int i=1;i<n;++i){
for(int j=i+1;j<=n;++j){
res=gcd(res,lcm(a[i],a[j]));
}
}
就像这样,但实际上会超时的。
那么可以采用一些优化措施,
(gcd({lcm({ai,aj}) | i<j})) 可以这样理解,
枚举每一个 (i) ,使 (c_i=lcm(a_i,a_j)) 满足 (i) 不变并且 (j>i) ,之后计算 (gcd(c_i))
那就是这样
for(int i=1;i<n;++i){
c[i]=a[i];
for(int j=i+1;i<=n;++j){
c[i]=lcm(c[i],a[j]);
}
}
int ret=c[1];
for(int i=2;i<n;++i){
ret=gcd(ret,c[i]);
}
你可能会发现一个规律,(c_i) 表示的是 (a_i) 和所有 (a_j) 的 (lcm)
(namo) ,提前预处理一下所有的 (lcm) 存储到 (b_i) 中。
后面的就是计算 (a_i) 和 (b_{i+1}) 的 (gcd) 了。
代码
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll a[maxn];
ll b[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
b[i]=a[i];
}
for(int i=n-1;i>0;--i){
b[i]=gcd(b[i+1],b[i]);
}
ll ret=a[1]*b[2]/gcd(a[1],b[2]);
for(int i=1;i<n;++i){
ret=gcd(ret,a[i]*b[i+1]/gcd(a[i],b[i+1]));
}
printf("%lld
",ret);
return 0;
}
D. Orac and Medians
题解
输出 (yes) 的一个必要条件是数组中存在 (k) ,其次是如果有两个连续的数大于等于 (k) 的话,(namo) 再加上任何一个小于 (k) 的话,这连续的三个数的值 都会大于等于 (k) ,此后依次吞噬小的数,当遇到k时,两个大于等于 (k) 的数放在一起会变成两个 (k) 的。经过这样之后剩下的都是数组可以想象出来都是什么样子的。
最后筛一个 (a_{i+1},a_{i-1}≥k) 并且(ai<k) 只要满足这种情况就会生成连续三个都大于等于 (k) 的数字。
总结一下就是满足下列条件之一就输出 (yes)
- 数组中存在 (k) 并且满足 (a_i,a_{i+1}≥k)
- 数组中存在 (k) 并且满足 (a_{i+1},a_{i-1}≥k,ai<k)
- (n=1) 并且存在 (k) (最坑的点)
代码
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn]={0};
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,k;
int flag=0,f=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
if(a[i]>=k&&a[i-1]>=k&&i!=1)flag=1;
if(a[i]>=k&&a[i-1]<k&&a[i-2]>=k&&i>=2)flag=1;
if(a[i]==k)f=1;
}
if(!f){
printf("no
");
continue;
}
if(flag||n==1){
printf("yes
");
continue;
}
printf("no
");
}
return 0;
}
E. Orac and Game of Life
题解
根据题意它内部的变化是上下左右有相同的则变,否则不进行改变,其次的话如果图中的某一个位置发生了变化,之后它的变化就会是周期性的变化。
现在要解决的问题就会是它什么时候发生变化,发生的变化来自于存在至少两个相等的位置扩散来的变化,就像这样
一遍 (bfs) 搜索一下,记录一下到达的时间,输出的时候判断一下规律就好了。
代码
#include <cmath>
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e3+5;
struct node{int x,y;ll val;};
int step[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
char s[maxn][maxn];
int vis[maxn][maxn];
ll dis[maxn][maxn];
int main(){
queue<node>Q;
int n,m,t;
scanf("%d%d%d",&n,&m,&t);
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
dis[i][j]=1e18+1;
}
}
for(int i=0;i<n;++i)scanf("%s",s[i]);
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
for(int k=0;k<4;++k){
int x=i+step[k][0];
int y=j+step[k][1];
if(x>=0&&x<n&&y>=0&&y<m&&s[x][y]==s[i][j]){
Q.push({i,j,0});
vis[i][j]=1;
dis[i][j]=0;
break;
}
}
}
}
while(!Q.empty()){
node p=Q.front();
Q.pop();
for(int i=0;i<4;++i){
int x=step[i][0]+p.x;
int y=step[i][1]+p.y;
if(x>=0&&x<n&&y>=0&&y<m&&!vis[x][y]){
// cout<<x<<" "<<y<<" "<<p.x<<" "<<p.y<<endl;
vis[x][y]=1;
dis[x][y]=p.val+1;
Q.push({x,y,dis[x][y]});
}
}
}
// for(int i=0;i<n;++i){
// for(int j=0;j<m;++j)
// cout<<dis[i][j]<<" ";
// cout<<endl;
// }
while(t--){
int x,y;
ll q;
scanf("%d%d%lld",&x,&y,&q);
x--;y--;
int val=s[x][y]-'0';
if(dis[x][y]<=q){
val=((q-dis[x][y])%2+val)%2;
printf("%d
",val);
}
else printf("%d
",val);
}
return 0;
}