CodeForces - 892 B C D

B - Wrath

题意&分析:

铃响杀人,一群犯人站成一排,每个人都有个爪子,长度为L_i
,当满足 j < i && j >= L_i - i 时 i 可以将 j 杀死。问最后有多少人活下来。

倒序遍历一遍,复杂度o( n ),对于每一个人都有一个可以杀人的区间,把这个区间里的人全部 kill 就可以了,求出最长的这个区间,去除掉之后剩下的就是答案。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll Mod = 1e9 + 7;

ll a[1000010];
ll vis[1000010];
ll n;
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    while(scanf("%lld",&n) != EOF){
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        ll kill = -1;
        memset(vis,0,sizeof(vis));
        for(int i=n;i>=1;i--){
            kill --;
            ll temp = a[i];
            if(kill >= 0)vis[i] = 1;
            kill = max(temp,kill);
        }
        ll ans = 0;
        for(int i=1;i<=n;i++){
            if(vis[i] == 0)ans ++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C - Pride

题意&分析:

一个数列,相邻两个数 x,y 可以求 GCD(x,y),并且可以替换x,y中的一个;问最后该数列是否可以全部变成 1 。

如果可以,则:

  若所有的数的GCD不是 1 ,那么输出 - 1;
  若所有的数的GCD是 1,则需要知道:原数列1的个数,如果有,直接输出 n - n0(1的个数);如果没有,则算出 通过gcd求出 1 的最少步骤;对于只有一个数字的情况,只有这个数字是1才满足,否则输出-1。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll Mod = 1e9 + 7;
const ll MAXN = 2010;

ll a[MAXN];
ll n;

ll gcd(ll a,ll b){
    return b==0? a:gcd(b,a%b);
}
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    while(scanf("%lld",&n) != EOF){
        ll cnt_one = 0;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            if(a[i] == 1)cnt_one ++;//需要计算原来的数组中的 1 ,这些事不需要在取gcd的,容易错。 
        }
        if(cnt_one){
            printf("%lld\n",n - cnt_one);continue;
        }
        ll tmp_gcd = a[1];
        for(int i=2;i<=n;i++){
            tmp_gcd = gcd(tmp_gcd,a[i]);
        }
        if(tmp_gcd != 1){//所有数的最大公约数不是 1 ,无解  e.g. 2 4 6 8
            printf("-1\n");continue;
        }
        ll step = 0,ans = INF;//step记录获得1而求gcd的次数 即两个数互质
        for(int i=1;i<=n;i++){
            tmp_gcd = a[i];
            for(int j=i+1;j<=n;j++){
                tmp_gcd = gcd(tmp_gcd,a[j]);
                if(tmp_gcd == 1){
                    step = j - i;break;
                }
            }
            ans = min(ans,step + n - 1 - cnt_one);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

D - Gluttony

题意&分析:

给定数列{an},元素互不相同,将{an}的元素重排列之后得到数列{bn},满足两数列前k项和S(ak) != S(bk);

对于一个有序的数列 a1,a2,…,an,可以构造出数列a2,a3,…,an,a1, 这样子显然可以得出前 k 项和是不会相等的。所以对于任意的一个数列{an},只需要将低 j 大的数用第 j-1 大的数替换,然后最小的那个数用最大的数替换即可。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll Mod = 1e9 + 7;
const ll MAXN = 30;

int a[MAXN],b[MAXN];
int n;


int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    while(scanf("%d",&n) != EOF){
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            b[i] = a[i];
        }
        sort(b,b+n);
        b[n] = b[0];
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(a[i] == b[j]){
                    printf("%d",b[j+1]);break;
                }
            }
            printf("%c",(i==n-1)? '\n':' ');
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值