cf 909 div.3题解(A-E)

A

传送门:Problem - A - Codeforces

如果一开始那个数就可以被3取余数,瓦尼亚先手改变了他的值,这样的话,这个数就再也不能被3整除了。其实仔细一想 , 只有 2 , 4 , -1 , 1这种数字,改变一下就能被整除的数字,瓦尼亚可以一次改变获得胜利,剩下的所有数字,瓦尼亚都赢不了

int n ;cin>>n;
    //玩家可以加一 或者减一
    if(!(n%3)){
        cout<<"Second"<<'\n';
        return;
        
    }
    if((n-1)%3 == 0 || (n+1)%3 == 0 || (n-1) == 0 || (n+1)==0){
        cout<<"First"<<'\n';
        return;
    }

B

传送门:Problem - B - Codeforces

这题就稍微难一点了,感觉是前三题里面最难的,主要是因为题目看不懂,不好理解(我这种高考语文118的人都理解了半天【手动狗头】)。好了 ,这里就说一下题目是什么意思,首先有n个箱子,我们把他们分成若干组,每组里面都有k个箱子。我们就得到了第一个条件k要是n的因数

然后呢,找到每组的重量 , 举个例子, 假设被分成1,2, 3三组,1组的重量是8,2组的重量是9,三组的重量是2。然后计算出差值最大的数,在例子中就是 9-2 = 7;那么这个7就是被分成3组时的答案 ,找到最大答案

我们用前缀和来维护每一组的和,这样子的话查询效率就从On 变成O1了

1、首先是找到n的因数

for(int i =1;i<=n;++i){

    if(n % i == 0){

        int k =i;  //k 的值 ,其实这步也可以不写
        int t =result(k);  //这是一个函数,我们一会来写这个函数
        ans = max(ans , t);
    }
}

这样子,基本框架就完成了

2、求出每组的和并找到差值最大的数

//刚刚的那个函数
int result(int k ){
    int maxn =-1;
    for(int i =1;i<=n;i +=k){
        maxn = max(maxn , pre[i+k-1] - pre[i-1]);  //找到了几组中和最大的数
    }
    //接下来找最小的
    int minn = 1e15;
    for(int i =1;i<=n;++i){
        minn = min(minn , pre[i-1+k] -pre[i-1]);
    }
    return maxn - minn;
}

到这里就做完了

#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 150010;
int a[N] , pre[N];
int n;
int result(int k){
    int maxn = -1;
    for(int i =1;i<=n;i +=k){
        maxn = max(maxn , pre[i +k-1] - pre[i-1]);
    }
    int minn = 1e15;
    for(int i =1;i<=n;i +=k){
        minn = min(minn , pre[i +k-1] - pre[i-1]);
    }
    return maxn - minn;
}

void solve(){
    cin>>n;
    for(int i =1;i<=n;++i)cin>>a[i];
    for(int i = 1;i<=n;++i)pre[i] = pre[i-1]+a[i];
    int ans = -1;
    for(int i =1;i<=n;++i){
        if(n%i ==0){
            int k = i;  //k值
            int t = result(k);
            ans = max(ans , t);
        }
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
    int _;cin>>_;
    while(_--)solve();
    return 0;
}

C

传送门:Problem - C - Codeforces

这道题其实就是最长连续上升子序列的变式,动态规划去做,但是我们要知道奇偶数连续怎么表示,其实就是((a[i] +a[i-1])&1),看不懂位运算的话,其实就是这样((a[i] +a[i-1])%2 != 0)

#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 2e5+9;
int a[N] , dp[N];
void solve()
{
   int n;cin>>n;
   for(int i  =1;i<=n;++i)cin>>a[i] , dp[i] = a[i];
   
   int ans = -1e9;
   for(int i =1;i<=n;++i){
       if((a[i]+a[i-1])&1)dp[i] = max(dp[i-1]+a[i] , dp[i]);
       ans = max(ans , dp[i]);
   }
   cout<<ans<<'\n';
}


signed main(){
    ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
    int _;cin>>_;
    while(_--)solve();
    return 0;
}

D

传送门:Problem - D - Codeforces

这题要求给定数列 a,求有多少对 (i,j) 满足 (2ai​)(2aj​)=(2aj​)(2ai​)。

我们可以把式子化简一下,我是用了取对数的方式,就变成 2^aj ln(2^ai) = 2^ai ln(2^ai)

我们可以看出只有ai = aj , ai =1 &&aj=2   , ai=2&&aj=1这三种情况的时候才能够满足题意

 那么我们就可以用map来存放

#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 2e5+9;
int a[N] ;
void solve()
{
    map<int,int>mp;
   int n;cin>>n;
   for(int i =1;i<=n;++i){
       cin>>a[i];
       mp[a[i]]++;
   }
   int ans = 0;
   for(auto [x,y]:mp){
       ans +=y*(y-1)>>1;
   }
   ans +=mp[2]*mp[1];
   cout<<ans<<'\n';
   
}


signed main(){
    ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
    int _;cin>>_;
    while(_--)solve();
    return 0;
}

E

传送门:Problem - E - Codeforces

我们只需要观察最小值,因为一旦最小值到了第一位,他将会永远在第一位,他后面的数就排不了序了,所以我们只需要看最小值后面的数有没有排好序,排好序的话,就有答案,答案是最小值的位置-1 , 反之就输出-1 。 还有需要注意的是,最小值是第一个出现的最小值

#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
#define INF 0x3f3f3f3f
const int N = 2e5+9;
int a[N] ;
void solve()
{
    int minn =1e10;
   int idx = 0;
   int n;cin>>n;
   for(int i =1;i<=n;++i){
       cin>>a[i];
       if(a[i] <minn){
           minn = a[i];
           idx = i;
       }
   }
   
   //idx 记录了第一个最小值的位置
   
   bool f = true;
   
   for(int i =idx+1;i<n;++i){
       if(a[i] >a[i+1])f = false;
       
   }
   if(f)cout<<idx-1<<'\n';
   else cout<<-1<<'\n';
   
   
   
}


signed main(){
    ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
    int _;cin>>_;
    while(_--)solve();
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值