C1.双声道(简易版)与C2.双声道题解与思路

题目链接 :
https://codeforces.com/contest/1855/problem/C1
https://codeforces.com/contest/1855/problem/C2
(c1为简单版)
解题思路 :
C1限制50次 , C2限制 31 次

那么对于这种题,我们先从特殊的情况去考虑
1.全是正数时
联想到前缀和可以想到,a2 + a1 > a1 ....
那么操作次数为19次
2.全是负数时
可以使用后缀和
操作次数为19次
3.有负有正时(划归思想)

对于C1,我们可以构造一个大于20的正数,然后转换成情况1,
倍增速度很快,最坏情况为
1 , 2 , 4 , 8 , 16 , 32共5次操作
把负数全部变成正数的最坏情况为19次操作
5 + 19 + 19 = 43 显然可以解决C1

对于C2
同样运用前缀思想是有利的
那么剩余的操作次数为31 - 19 = 12

设正数n1个,负数n2个,
正数最大值o1 , 负数最大值 o2

于是我们可以想到

当n1 <= 12 时,是否满足abs(o2) >= o1,使其正好12次操作内变成情况1或者情况2
那么它的对立面就是
当n2 <= 12时,o1 >= abs(o2)

如果对于第二个条件都不满足
那么我们去看另一个条件
n1 <= 7
那么我们构造一个大于20的负数
最坏情况为5次操作
全变负数 7次操作
前缀操作19次
5 + 7 + 19 = 31正好成立
那么它的对立面是
n2 <= 7
此题便已解决了
c1代码
 

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define endl '\n'
#define pii pair <ll , ll>
const ll N = 2e5 + 10;
const ll mod = 33789051;
const ll INF = 1e9 + 10;
ll a[N];

void slove() {
  ll n; cin >> n;
  ll op1 = 0 , op2 = 0;
  ll zz;
  for(ll i = 1 ; i <= n ; i++){
    cin >> a[i];
    if(a[i] > 0) op1 = a[i],zz = i;
    else if(a[i] < 0) op2 = a[i];
  }
  vector <pii> ans;
  if(op1 != 0 && op2 == 0){
    for(ll i = 2 ; i <= n ; i++){
      ans.push_back({i , i - 1});
    }
  }
  else if(op1 == 0 && op2 != 0){
    for(ll i = n - 1 ; i >= 1 ; i--){
      ans.push_back({i , i + 1});
    }
  }
  else if(op1 != 0 && op2 != 0){
    while(a[zz] < 20){
      a[zz] += a[zz];
      ans.push_back({zz,zz});
    }
    for(ll i = 1 ; i <= n ; i++){
      ans.push_back({i,zz});
    }
    for(ll i = 2 ; i <= n ; i++){
      ans.push_back({i,i - 1});
    }
  }
  cout << ans.size() << endl;
  for(auto x : ans){
    cout << x.first << " " << x.second << endl;
  }
}
int main()
{
    //freopen("classroom.in", "r", stdin);
    //freopen("classroom.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int tt = 1;
    cin >> tt;
    while (tt--) slove();
    return 0;
}

c2代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define endl '\n'
#define pii pair <ll , ll>
const ll N = 2e5 + 10;
const ll mod = 33789051;
const ll INF = 1e9 + 10;
ll a[N];

void slove() {
  ll n; cin >> n;
  ll n1 = 0 , n2 = 0;
  ll o1 = 0 , o2 = 0;
  ll z1 = 0 , z2 = 0;

  for(ll i = 1 ; i <= n ; i++){
    cin >> a[i];

    if(a[i] > 0){
      if(o1 < a[i]){
        o1 = a[i];
        z1 = i;
      }
      n1++;
    }

    if(a[i] < 0){
      if(o2 > a[i]){
        o2 = a[i];
        z2 = i;
      }
      n2++;
    }

  }
  vector <pii> ans;
  if(n1 > 0 && n2 == 0){
    for(ll i = 2 ; i <= n ; i++){
      ans.push_back({i , i - 1});
    }
  }

  else if(n1 == 0 && n2 > 0){
    for(ll i = n - 1 ; i >= 1 ; i--){
      ans.push_back({i , i + 1});
    }
  }
  else if(n1 > 0 && n2 > 0){
    if(n1 <= 12 && abs(o2) >= o1){
      for(ll i = 1 ; i <= n ; i++){
        if(a[i] > 0){
          ans.push_back({i,z2});
        }
      }
      for(ll i = n - 1 ; i >= 1 ; i--){
        ans.push_back({i,i + 1});
      }
    }
    else if(n2 <= 12 && o1 >= abs(o2)){
      for(ll i = 1 ; i <= n; i++){
        if(a[i] < 0){
          ans.push_back({i , z1});
        }
      }
      for(ll i = 2 ; i <= n ; i++){
        ans.push_back({i , i - 1});
      }
    }
    else if(n1 <= 7){
      while(a[z2] > -20){
        a[z2] += a[z2];
        ans.push_back({z2 ,z2});
      }
      for(ll i = 1 ; i <= n ; i++){
        if(a[i] > 0){
          ans.push_back({i , z2});
        }
      }
      for(ll i = n - 1 ; i >= 1 ; i--){
        ans.push_back({i, i + 1});
      }
    }
    else if(n2 <= 7){
      while(a[z1] < 20){
        a[z1] += a[z1];
        ans.push_back({z1,z1});
      }
      for(ll i = 1 ; i <= n ; i++){
        if(a[i] < 0){
          ans.push_back({i , z1});
        }
      }
      for(ll i = 2 ; i <= n ; i++){
        ans.push_back({i , i - 1});
      }
    }
  }
  cout << ans.size() << endl;
  for(auto x : ans){
    cout << x.first << " " << x.second << endl;
  }
}
int main()
{
    //freopen("classroom.in", "r", stdin);
    //freopen("classroom.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int tt = 1;
    cin >> tt;
    while (tt--) slove();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值