Codeforces Round #641 (Div. 2) 补题


A. Orac and Factors
一个偶数每次操作后都会加2,一个奇数第一次操作后会变成偶数

代码

#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
ll mod = 1e9 + 7;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int t;
    cin>>t;
    while(t--){
        int n, k;
        read(n), read(k);
        ll ans = 0;
        if(n%2 == 0){
            ans = 1ll*n + 1ll*2*k;
        }
        else{
            ll div = n;
            for(int i=2;i*i<=n;i++){
                if(n%i == 0){
                    div = i;
                    break;
                }
            }
            ans = n + div + 1ll*2*(k-1);
        }
        cout<<ans<<"\n";
    }
 	return 0;
}
 
 

B. Orac and Models
用动态规划的方法,mx[i]代表从第i个数出发能得到的最大结果。从后向前遍历,对于第i个元素a[i],遍历每次走一步,每次走两步....能得到的值,例如能从i走到j,那么有转移方程mx[i] = max(mx[i], mx[j] + 1)

代码

#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
ll mod = 1e9 + 7;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int a[100050];
int mx[100050];
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int t;
    cin>>t;
    while(t--){
        int n;
        read(n);
        for(int i=1;i<=n;i++) scanf("%d", &a[i]);
        int ans = 0;
        for(int i=n;i>=1;i--){
            mx[i] = 1;
            for(int j=i+i;j<=n;j+=i){
                if(a[j] > a[i])
                    mx[i] = max(mx[i], mx[j] + 1);
            }
            ans = max(ans, mx[i]);
        }
        //for(int i =1;i<=n;i++) cout<<mx[i]<<endl;
        cout<<ans<<"\n";
    }
 	return 0;
}
 

C. Orac and LCM
我的方法好像比较麻烦。。。
以4,6,,9为例
| | 4 | 6 | 9 |
| 2 | 2 | 1 | 0 |
| 3 | 0 | 1 | 2 |
用这个格子表示每个数中含有某个素因数的个数,比如4里面有2个2,0个3。考虑对任意两个数取lcm对素因数的影响,比如对4和6取lcm,所得到的数中因数2的个数就是max(2, 1)=2,6和9取lcm所得到的数中素因数2的个数是max(1,0)=0。而取lcm所得到的集合取gcd保留的素因数2的个数就是所有数含素因数2的个数的最小值,所以我们就可以考虑求出在对任意两数取lcm后可以得到的每个素因数的最小值,如果把每个数含素因数2的个数放进一个数组,那么在取gcd时2对答案的贡献就是这个数组中倒数第二小的值(因为最小值和次小值也会取一次lcm保留次小值)。至此我们可以想到,对每个元素分解素因数,记录每种素因数的次小个数,最后所有素因数按次小个数乘起来就是答案。

代码

#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
ll mod = 1e9 + 7;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int gcd(int a, int b){
    return b==0?a:gcd(b, a%b);
}
int a[100050];
int mi[200050], _mi[200050];
int sz[200050];
int mx = 0;
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int n;
    cin>>n;
    memset(mi, INF, sizeof(mi));
    memset(_mi, INF, sizeof(_mi));
    for(int i=1;i<=n;i++){
        read(a[i]);
        mx = max(mx, a[i]);
        int t = a[i];
        for(int j=2;j*j<=t;j++){
            int num = 0;
            while(a[i]%j==0){
                a[i] /= j;
                num++;
            }
            if(num < mi[j]){
                _mi[j] = mi[j];
                mi[j] = num;
            }
            else _mi[j] = min(_mi[j], num);
            sz[j]++;
            
        }
 
        if(a[i]!=1){
            int num = 1;
            int j = a[i];
            if(num < mi[j]){
                _mi[j] = mi[j];
                mi[j] = num;
            }
            else _mi[j] = min(_mi[j], num);
            sz[a[i]]++;
        }
    }
    ll ans = 1;
    for(int i=1;i<=mx;i++){
        if(sz[i] == n) ans *= 1ll*pow(i, _mi[i]);
        else if(sz[i] == n-1) ans *= 1ll*pow(i, mi[i]);
    }
    cout<<ans<<endl;
 	return 0;
}


D. Orac and Medians
这题的模型就和病毒传播一样。。。
因为大小只是相对关系,读入数据时比k大的元素记为2,等于k的记为1,小于k的记为0
如果数组里不含1,那么肯定是不满足的
如果连着的三个数中有两个大于零的元素,那么我们就可以把剩下的那个元素也变成大于零的数,在这样的操作下,如果数组中元素是0,0,x,1,0,0,0重复这样的操作我们就可以把所有元素变为1(x>0),如果数组是2,2,0,0,0,1,0,0虽然2与1距离很远,但我们可以通过上述操作把数组变成2,2,2,2,2,1,0,0之后我们就可以把数组变成全1
所以这道题在判断有没有1之后判断数组中有没有两个大于零的元素,他们距离小于等于2

代码
#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
ll mod = 1e9 + 7;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int a[100005];
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int t;
    cin>>t;
    while(t--){
        int n, k;
        cin>>n>>k;
        bool flag = false;
        for(int i=1;i<=n;i++){
            int v;
            read(v);
            if(v == k) a[i] = 1;
            else if(v > k) a[i] = 2;
            else a[i] = 0;
            if(v == k) flag = true; 
        }
        if(!flag){
            printf("no\n");
            continue;
        }
        if(n==1){
            printf("yes\n");
            continue;
        }
        flag = false;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n&&j-i<=2;j++){
                if(a[i]&&a[j]){
                    flag = true;
                    break;
                }
            }
            if(flag) break;
        }
        if(flag) printf("yes\n");
        else printf("no\n");
    }
 	return 0;
}

E. Orac and Game of Life
如果一个数能变色,那么他就一直能变色(因为相邻的格子也在一起变色),如果一个格子不能变色,那么会变色的格子在几轮之后可能会“传播”到他这里,让他能够变色,所以这个题就是统计每个格子最少几轮后开始变色

代码
#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
ll mod = 1e9 + 7;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int n, m, t;
int a[1005][1005], mi[1005][1005];
bool vis[1005][1005];
int mx[4] = {0, 0, 1, -1}, my[4] = {1, -1, 0, 0};
queue<int> q;
void bfs(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=0;k<4;k++){
                int xx = i + mx[k];
                int yy = j + my[k];
                if(xx<1||xx>n||yy<1||yy>m) continue;
                if(a[i][j]==a[xx][yy]){
                    vis[i][j] = 1;
                    mi[i][j] = 0;
                    q.push(i), q.push(j);
                    break;
                }
            }
        }
    }

    while(!q.empty()){
        int x = q.front(); q.pop();
        int y = q.front(); q.pop();
        for(int k=0;k<4;k++){
            int xx = x + mx[k];
            int yy = y + my[k];
            if(vis[xx][yy]||xx<1||xx>n||yy<1||yy>m) continue; 
            vis[xx][yy] = 1;
            mi[xx][yy] = mi[x][y] + 1;
            q.push(xx), q.push(yy);
        }
    }
} 
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            char v;
            cin>>v;
            a[i][j] = v - '0';
            mi[i][j] = INF;
        }
    }
    bfs();
    
    while(t--){
        int x, y;
        ll p;
        cin>>x>>y>>p;
        if(mi[x][y]>p||mi[x][y]==INF||(p+mi[x][y])%2==0){//cout<<p+mi[x][y]<<"m"<<endl;
            printf("%d\n", a[x][y]);
            continue;
        }
        else printf("%d\n", !a[x][y]);
    }
 	return 0;
}


posted @ 2020-05-14 00:28  DinoMax  阅读(139)  评论(0)    收藏  举报