【CodeForces】CF Round 641 (Div.2)
比赛时秒了 \(A\) 和 \(B\),然后后面又肝出了 \(C\) 然后 \(D\) 不会做滚粗。最终 rating \(+97\) 上蓝。
A. Orac and Factors
显然是个结论题。推一下便可发现,对于一个 \(n\):
若 \(n\) 是质数,那么它的变化必然是 \(n\to 2n\to 2n+2\to 2n+4\to ... \to 2n+2(k-1)\),所以答案是 \(2(n+k-1)\)
若 \(n\) 是合数,那么它加上自己的最小质因子肯定是偶数,设 \(s_i\) 为 \(i\) 的最小质因子,所以必然是 \(n\to n+s_n\to n+s+2\to ... \to 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\n",2*(n+k-1));
}else{
printf("%lld\n",n+sm[n]+2*(k-1));
}
}
return 0;
}
B. Orac and Models
很思博的一个 \(dp\) 题。就是按照最长单调递增子序列的方法做,然后只有自己的约数可以转移到自己。\(O(n\sqrt{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\n",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\n",a[x][y]);
else printf("%d\n",a[x][y]^(max(p-f[x][y]+1,0ll)%2));
}
return 0;
}