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;
}