比赛时秒了 (A) 和 (B),然后后面又肝出了 (C) 然后 (D) 不会做滚粗。最终 rating (+97) 上蓝。
A. Orac and Factors
显然是个结论题。推一下便可发现,对于一个 (n):
若 (n) 是质数,那么它的变化必然是 (n o 2n o 2n+2 o 2n+4 o ... o 2n+2(k-1)),所以答案是 (2(n+k-1))
若 (n) 是合数,那么它加上自己的最小质因子肯定是偶数,设 (s_i) 为 (i) 的最小质因子,所以必然是 (n o n+s_n o n+s+2 o ... o n+s_n+2(k-1)),所以答案是 (n+s_n+2(k-1))。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+9;
int sm[N]; bool npr[N];
void pr(){
npr[1]=1;
for(int i=2;i<=1000000;i++){
if(!npr[i]){
for(int j=i;j<=1000000/i;j++)
if(!npr[i*j]) sm[i*j]=i,npr[i*j]=1;
}
}
}
signed main(){
int T; cin>>T;
pr();
while(T--){
int n,k; scanf("%lld%lld",&n,&k);
if(!npr[n]){
printf("%lld
",2*(n+k-1));
}else{
printf("%lld
",n+sm[n]+2*(k-1));
}
}
return 0;
}
B. Orac and Models
很思博的一个 (dp) 题。就是按照最长单调递增子序列的方法做,然后只有自己的约数可以转移到自己。(O(nsqrt{n}))
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N],f[N];
int main(){
int T; cin>>T;
while(T--){
int n; scanf("%d",&n); int ans=1;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=sqrt(i);j++){
if(i%j==0){
if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);
if(a[i/j]<a[i]) f[i]=max(f[i],f[i/j]+1);
}
}
ans=max(ans,f[i]);
}
printf("%d
",ans);
}
return 0;
}
C. Orac and LCM
我们可以推得,如果有一个质因子同时不在两个数中出现,设这两个数为 (a_i) 和 (a_j),那么 (operatorname{lcm} (a_i,a_j)) 肯定不包含这个质因子,所以最终的答案中不会有这个质因子。
所以一个质因子在答案中出现的必要条件是这个质因子必须在至少 (n-1) 个数中出现。
我们考虑每个数的指数。如果这个数在由于最终的 (operatorname{gcd}) 中这个质因子的指数应该是所有 (lcm) 中的指数的最小值。如果这个数在 (n-1) 个数中出现过,那么肯定就是在原数列中这个质因子出现的指数的最小值。如果在 (n) 个数都包含这个质因子,那么就是次小值。统计一下出现次数,指数最小值和次小值即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=100009;
int n,a[N],cnt[N*2],mn[N*2],cmn[N*2],ans=1; bool npr[2*N];
void pr(){
npr[1]=1;
for(int i=2;i<=N*2-10;i++){
if(!npr[i]){
for(int j=i;j<=(N*2-10)/i;j++)
if(!npr[i*j]) npr[i*j]=1;
}
}
}
int qp(int a,int b){
return (b==0?1:(b%2?qp(a*a,b/2)*a:qp(a*a,b/2)));
}
signed main(){
scanf("%lld",&n);
pr();
memset(mn,0x3f,sizeof(mn)),memset(cmn,0x3f,sizeof(cmn));
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
for(int j=1;j<=sqrt(a[i]);j++){
if((a[i]%j==0)&&(!npr[j])){
cnt[j]++;
int tmp=a[i],tot=0;
while(tmp%j==0){
tot++,tmp/=j;
}
if(tot<=mn[j]) cmn[j]=mn[j],mn[j]=tot;
else if(tot<cmn[j]) cmn[j]=tot;
}
if((a[i]%j==0)&&(!npr[a[i]/j])&&(a[i]/j!=j)){
cnt[a[i]/j]++;
int tmp=a[i],tot=0;
while(tmp%(a[i]/j)==0){
tot++,tmp/=(a[i]/j);
}
if(tot<=mn[a[i]/j]) cmn[a[i]/j]=mn[a[i]/j],mn[a[i]/j]=tot;
else if(tot<cmn[a[i]/j]) cmn[a[i]/j]=tot;
}
}
}
for(int i=2;i<=N*2-10;i++){
if((!npr[i])&&cnt[i]==n) ans*=qp(i,cmn[i]);
else if(!npr[i]&&cnt[i]==n-1) ans*=qp(i,mn[i]);
}
printf("%lld",ans);
return 0;
}
D. Orac and Medians
这道题有一个转换,就是其实只有 (3) 种数,大于 (k),小于 (k) 和等于 (k),我们分别转换为 (2),(0),(1)。我们要把所有区间化为 (1)。
如果这个序列没有 (1),那么答案肯定是no
。
然后我们可以发现,(2) 的影响不大,因为一旦 (1) 和 (2) 相邻,那么合并一下一定是 (1)。但是 (0) 的影响就很大。对于一个长度为 len 的区间,一旦中位数是 (0) 那么这个区间就是 (0),所以我们要判断是不是所有区间的中位数都是 (0)。
我们化简亿下这个条件。一旦一个区间是可以化成 (1) 的,那么一定存在一个长度为 (3) 的区间是可以化成 (1) 的;如果所有区间都不可以,那么所有长度为 (3) 的也都不可以。所以我们只需要判断长度为 (3) 的即可。存在这样的区间,就是存在一个长度为 (3) 的区间使得里面 (0) 的个数不大于 (1)。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+9;
int a[N],s[N];
int main(){
int T; cin>>T;
while(T--){
bool ans=0;
int n,k; scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]>=k) s[i]=s[i-1]+1;
else s[i]=s[i-1];
if(a[i]==k) ans=1;
}
if(!ans){puts("no");continue;}
ans=0;
for(int i=1;i<=n-2;i++){
ans|=(s[i+2]-s[i-1]>1);
}
if(n==1) ans=(a[n]==k);
if(n==2) ans=((a[1]==k&&a[2]>=k)||(a[2]==k&&a[1]>=k));
if(ans) puts("yes");
else puts("no");
}
return 0;
}
E. Orac and Game of Life
一个方格如果在当前回合变化了,那么下一个回合也会变化。所以假设知道了这个方格是在第 (f_{i,j}) 回合第一次变化,那么我们可以很快的求出他在第 (k) 个回合的状态。
如果一个方格在第 (j) 回合变化,那么在第 (j+1) 回合,它周围所有还没有变化的方格都会开始变化。所以这相当于一个向外扩散的过程(想象一下共振),我们可以用 BFS 解决。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+9;
int n,m,t,a[N][N],f[N][N]; bool vst[N][N];
bool ok(int x,int y){return x>0&&x<=n&&y>0&&y<=m;}
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
struct node{int x,y;};
void bfs(){
queue<node>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
bool move=0;
for(int k=0,nx,ny;k<4;k++)
move|=(ok(nx=i+dx[k],ny=j+dy[k])&&a[i][j]==a[nx][ny]);
if(move) q.push((node){i,j}),f[i][j]=1,vst[i][j]=1;
}
while(!q.empty()){
int x=q.front().x,y=q.front().y; q.pop();
for(int k=0,nx,ny;k<4;k++)
if(ok(nx=x+dx[k],ny=y+dy[k])&&!vst[nx][ny]){
f[nx][ny]=f[x][y]+1;
q.push((node){nx,ny});
vst[nx][ny]=1;
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;i++){
string s; cin>>s;
for(int j=1;j<=m;j++) a[i][j]=s[j-1]-'0';
}
bfs();
for(int i=1,x,y;i<=t;i++){
long long p; scanf("%d%d%lld",&x,&y,&p);
if(f[x][y]==0) printf("%d
",a[x][y]);
else printf("%d
",a[x][y]^(max(p-f[x][y]+1,0ll)%2));
}
return 0;
}