Codeforces Round #693 (Div. 3)部分题解

Codeforces Round #693 (Div. 3) 部分题解

D. Even-Odd Game

思路: 贪心田忌赛马

(1)先将数组从大到小排序,取数时从大到小取,用一个ans变量记录取数的过程

(2)ALice取数时,如果当前数是偶数,则ans加上相应的数(当前为最大数为偶数,显然取数对Alice有利),否则当前数是奇数,不取,ans不变

(3)Bob取数时,如果当前数是奇数,则ans减去相应的数(当前为最大数为奇数,显然取数对Bob有利),否则当前数是偶数,不取,ans不变

(4)ans > 0 ALice获胜, ans < 0 Bob获胜, ans = 0 平局 

代码: 

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define maxn 200005
#define mod 1000000007
using namespace std;
 
long long a[maxn];
bool cmp(int a, int b)
{
  return a > b;
}
void solve()
{
  int n;
  cin >> n;
  for(int i = 0; i < n; i++)
    cin >> a[i];
 
  sort(a, a+n, cmp);
  long long ans = 0;
  for(int i = 0; i < n; i++)
  {
    if(i % 2 == 0)
    {
      if(a[i] % 2 ==0) ans += a[i];
    }
    else
    {
      if(a[i] % 2 == 1) ans -= a[i];
    }
  }
  if(ans > 0) cout << "Alice" << endl;
  else if(ans < 0) cout << "Bob" << endl;
  else cout << "Tie" << endl;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
      solve();
    }
 
    return 0;
}

E. Correct Placement

思路:排序二分查找

(1)为简化问题,当输入数据hi > wi时交换两者,使hi总是两者较小数,wi总是两者较大数,这样就只用考虑wj < wi 且 hj < hi的情况

(2)用结构体数组存储每个人的hi,wi值,将数组按照hi升序排序,如果hi值相同则按wi值升序排序

(3)对于第i个人,用一个min_wi_index值记录结构体数组前i-1个人中hi 小于第i个人 且 wi值最小的下标

(4)对于每个人,先在结构体数组中二分查找他的位置,那么在他之前的人一定能保证hi值小于等于他,再与min_wi_index下标对应的wi比较, 如果大于该wi,则说明有人可以排在该人前面,输出下标

代码:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define maxn 200005
#define mod 1000000007
using namespace std;
 
struct node{
  long long wi, hi;
  int index;
  int min_wi_index;
}n1[maxn], n2[maxn];
long long wi[maxn],hi[maxn];
bool cmp1(node n1, node n2)
{
   if(n1.hi != n2.hi) return n1.hi < n2.hi;
   else return n1.wi < n2.wi;
}
 
int divide(int left, int right, int hi, int wi)
{
  int Index;
  while(left <= right)
  {
    int mid = (left + right)/2;
 
    if(n1[mid].hi == hi && n1[mid].wi == wi)
    {
      Index = n1[mid].min_wi_index;
      if(Index != -1 && n1[Index].hi < hi && n1[Index].wi < wi)
        return n1[Index].index;
      else
        return -1;
    }
    else if(n1[mid].hi > hi || (n1[mid].hi == hi && n1[mid].wi > wi))
      right = mid - 1;
    else if(n1[mid].hi < hi || (n1[mid].hi == hi && n1[mid].wi < wi))
      left = mid + 1;
 
  }
}
int main()
{
    int t;
    cin >> t;
    for(int i = 1; i <= t; i++)
    {
      int n;
      cin >> n;
      for(int i = 0; i < n; i++)
      {
        cin >> hi[i] >> wi[i];
        if(hi[i] > wi[i]) swap(hi[i], wi[i]);
        n1[i].hi = hi[i];
        n1[i].wi = wi[i];
        n1[i].index = i+1;
        n1[i].min_wi_index = -1;
      }
      sort(n1, n1+n, cmp1);
      int j = 0;
      int Min_wi = 1e18;
      int Min_index;
      for(int i = 0; i < n; i++)
      {
        while(j < i && n1[j].hi < n1[i].hi)
        {
          if(n1[j].wi < Min_wi)
          {
            Min_index = j;
            Min_wi = n1[j].wi;
          }
          j++;
        }
        if(Min_wi < n1[i].wi) n1[i].min_wi_index = Min_index;
      }

      for(int i = 0; i < n; i++)
      {
        int ans1 = divide(0, n-1, hi[i], wi[i]);
        printf("%d%c", ans1, i == n-1?'\n':' ');
 
      }
    }
 
    return 0;
}

F. New Year's Puzzle

思路:排序思维

看数据规模,输入瓷砖数达到1e9,而阻挡的瓷砖数只有1e5,显然从阻挡的瓷砖数下手

我们考虑每一列,分下列几种情况来讨论:

(1)如果该列全空,即没有阻挡的瓷砖,则可以直接用2x1瓷砖来填充

(2)如果该列全满,即都是阻挡的瓷砖,则没有操作余地

(3)如果该列有一个阻挡块,则只能用1x2瓷砖来填充

从以上情况可以看出,如果出现列中只有一个阻挡块的情况,那么必须和后面阻挡的瓷砖结合起来,下面用图示来说明一个阻挡块的情况

黑色填充表示阻挡块,其他颜色表示普通瓷砖

第一种情况,两列的阻挡块在不同行时,它们所在的列数差为偶数时,能够形成填充

第二种情况,两列的阻挡块在同行时,它们所在的列数差为奇数时,能够形成填充

第三种情况,后面的阻挡块有两块在同一列时,无法形成填充

最后,得到这道题的整体思路:

(1)有奇数个阻挡块时可以不需要处理,因为所有瓷砖数必定为偶数,因此最后需要填充奇数块瓷砖,必定无法实现

(2)将所有阻挡块按照列升序排序,如果列相同则按行升序排序,同时一个map记录所有阻挡块的位置

(3)用一个state变量记录当前填充的状态,1代表前面有单个阻挡块在一列的情况,需要处理;0代表没有需要处理

         的阻挡块,如果当前存在有单个阻挡块在一列的情况,则需要记录,将state值变为1

(4)遍历所有阻挡块,会出现四种情况:

         1.state = 0 且 当前列为一个阻挡块,则需要结合后面阻挡块处理,state变为1,同时记录位置信息;

         2.state = 0 且 当前列为两个阻挡块,则不需要处理,可以直接跳过 

         3.state = 1 且 当前列为一个阻挡块,则按照上述图示情况进行处理判断

         4.state = 1 且 当前列为两个阻挡块,无法处理,结束遍历

代码:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define maxn 200005
using namespace std;
 
struct node
{
  int ri,ci;
}s[maxn];
 
bool cmp(node n1, node n2)
{
  if(n1.ci != n2.ci) return n1.ci < n2.ci;
  else return n1.ri < n2.ri;
}
string to_String(int a, int b)
{
  stringstream ss;
  string s;
  ss << a << b;
  ss >> s;
  return s;
}
void solve()
{
  int n,m;
  cin >> n >> m;
  map<string, bool> mp;
  map<int, int> cnt;
  for(int i = 0; i < m; i++)
  {
    cin >> s[i].ri >> s[i].ci;
    cnt[s[i].ci]++;
    mp[to_String(s[i].ri, s[i].ci)] = true;
  }
  sort(s, s+m, cmp);
  int flag = 1;
  if(m % 2 == 1) flag = 0;
  else
  {
    int state = 0;
    int nowri2 = 0, nowci2 = 0;
    int nowri1 = 0, nowci1 = 0;
 
    for(int i = 0; i < m; i++)
    {
      if(mp[to_String(nowri1, nowci1)] || mp[to_String(nowri2, nowci2)])
      {
        flag = 0;
        break;
      }
 
      if(!state && cnt[s[i].ci] != 2)
      {
        nowri1 = nowri2 = (s[i].ri == 1? 2:1);
        nowci1 = s[i].ci;
        nowci2 = s[i].ci + 1;
        state = 1;
        continue;
      }
      else if(state && cnt[s[i].ci] != 2)
      {
        int length = s[i].ci - nowci2;
        if(s[i].ri == nowri2)
        {
          if(length % 2 != 1)
          {
            flag = 0;
            break;
          }
          else state = 0;
        }
        else
        {
          if(length % 2 != 0)
          {
            flag = 0;
            break;
          }
          else state = 0;
        }
      }
      else if(state && cnt[s[i].ci] == 2)
      {
        flag = 0;
        break;
      }
    }
 
  }
  if(flag) cout << "YES" << endl;
  else  cout << "NO" << endl;
}
 
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
      solve();
    }
 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值