Codeforces Round #654 (Div. 2) A-D 题解

A、Omkar and Completion

https://codeforces.com/problemset/problem/1372/A
题意:
题目给出一个数n,要求输出一个n长度的数组(范围[1,1000]),对于数组中任意的x,y,z,有x + y != z,数组元素可以重复。
思路:
很简单,数组元素都相同即可。

代码:

#include
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int t,n;

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            printf("%s%d",i==0?"":" ",1);
        }
        printf("\n");
    }
    return 0;
}

B、Omkar and Last Class of Math

https://codeforces.com/problemset/problem/1372/B
题意:
给出一个数n,求两个数a和b,使得a+b=n且LCM(a,b)(就是a和b的最小公倍数)最小。
思路:
当n是偶数时,必然a和b都等于n/2
当n是奇数且是素数时,a和b分别是1和n-1
当n是奇数且不是素数时,a和b分别是n/x,n-n/x,这里的x是n的最小质因数
代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int t,n;
int tmp;//记录非质数的奇数最小的因数

bool judge(int x){//判断素数
    if(x==1) return false;
    if(x==2) return true;
    for(int i=2;i<=(int)sqrt(x);i++){
        if(x%i==0){
            tmp=i;
            return false;
        }
    }
    return true;
}

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        if(n%2==0){//若n是偶数,就是n/2
            printf("%d %d\n",n/2,n/2);
        }else{
            if(judge(n)){//如果n是奇数而且是素数
                printf("%d %d\n",1,n-1);
            }else{//如果n是奇数而且不是素数
                printf("%d %d\n",n/tmp,n-n/tmp);
            }
        }
    }
    return 0;
}

C、Omkar and Baseball

https://codeforces.com/problemset/problem/1372/C
题意:
给出一个大小为 n的排列,每次操作可以选取一个连续子数组任意排列其中的元素,要求每个元素的位置必须与操作前不同,问将排列排为1-n的顺序至少需要操作多少次。
思路:
(1)已经排好了,0次操作。
(2)只有一段连续区间都不在自己的位置,1次操作。
(3)其他的情况两次操作。
证明:
两次都操作整个数组。
第一次:选取整个数组,将所有ai = i的视为一体,在这个整体中每个元素循环右移一位,将余下 ai != i的元素各自归位后也视为一体,在这个整体中的每个元素也循环右移一位。
第二次:选取整个数组,将第一次的两个整体中的元素各自循环左移一位。


比如题目给的3 2 4 5 1 6 7
第一次:2 6 7在正确的位置,所以将2 6 7变为 7 2 6
3 4 5 1不在正确的位置,所以将3 4 5 1归位变为1 3 4 5
此时数组变为1 7 3 4 5 2 6
因为要进行第二次操作,所以继续把1 3 4 5右移一位,数组变为5 7 1 3 4 2 6
第二次:两个整体都在各自里面左移一位。

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 200005
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int t,n;
int a[MAX];

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int cnt=0;
        bool flag=false;
		for(int i=1;i<=n;i++){
			if(a[i]!=i&&!flag) flag=true,cnt++;
			else if(a[i]==i) flag=false;
		}
		if(!cnt) printf("0\n");
		else if(cnt==1) printf("1\n");
		else printf("2\n");
    }
    return 0;
}

D、Omkar and Circle

https://codeforces.com/problemset/problem/1372/D
题意:
给出n个数,可以将一个位置相邻的两个数求和,然后把当前位置的数替换为这两个数的和。不断操作直到剩下一个数,求这个数的最大值。
思路:
总共需要删除int(n / 2)个数,然后对剩下的数求和,且每次选择的位置不相邻。分别利用b和c数组求得(不相邻的)前缀和及(不相邻的)后缀和。
Codeforces Round #654 (Div. 2) A-D 题解_第1张图片
代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 200005
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int n;
ll a[MAX],b[MAX],c[MAX];

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%lld",&a[i]);
    }
    for(int i=0;i<n;i++){
        if(i<2) b[i]=a[i];
        else b[i]=b[i-2]+a[i];
    }
    for(int i=n-1;i>=0;i--){
        if(i>n-3) c[i]=a[i];
        else c[i]=c[i+2]+a[i];
    }
    ll ans=b[0];
    for(int i=0;i<n;i++){
        ans=max(ans,b[i]+c[i+1]);
    }
    printf("%lld",ans);
    return 0;
}

你可能感兴趣的:(codeforces)