Codeforces Round #641 (Div. 2)

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

题解

根据题意它内部的变化是上下左右有相同的则变,否则不进行改变,其次的话如果图中的某一个位置发生了变化,之后它的变化就会是周期性的变化。

现在要解决的问题就会是它什么时候发生变化,发生的变化来自于存在至少两个相等的位置扩散来的变化,就像这样

[0101\1010\0100\---\第一次 \0101\1011\0111\---\第二次\0100\1000\0000\---\第三次\0111\1111\1111\---\第四次\0000\0000\0000\ ]

一遍 (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;
}
新赛季的开始
原文地址:https://www.cnblogs.com/VagrantAC/p/12884384.html