2019 ICPC Asia Taipei-Hsinchu Regional
比赛小tip(要改进!
1.J题一定要看清数据范围,不然就很容易想岔了
2.如果两个人都统一了思路,一个人拿不定(没有别的题目可以出了),可以看着一个人打代码,防止思路到手上,就飞了!!
3.(个人)要注意板子代表什么,比如我的旋转卡壳板子,以及运用板子有发生什么比如nS发小返回0,用一次,改变参数, 我的旋转卡壳中间n有加加操作,n的含义在本函数后面改变了。//叉积算的值就是三角形面积,(我是笨蛋
碎碎念)理解板子这么来的,我用的就是叉积来求最远点对的鸭,那就别直接使用的了鸭,而求最大面积用的就是叉积。
J题
题意
T组数据
给出n,m,m行,每行有n个由0或者1组成的元素
问最少选几组,可以使得每个位置至少覆盖了一次
0 < n <= 500,0 < m <= 15
题解
暴力做,开(1<<m)大小的数组,这个数用二进制表示,如果二进制上为1,则选了该数组。
可以用bitset做,快!!!比int快32倍左右!
#include <bits/stdc++.h>
using namespace std;
inline int count(int tmp) {
int cnt = 0;
while(tmp) {
if(tmp & 1) cnt++;
tmp >>= 1;
}
return cnt;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, m;
scanf("%d%d", &n, &m);
bitset<510> a[20];
for(int i = 0; i < m; i++) {
cin >> a[i];
}
int ans = n + 1;
for(int i = 0; i < (1 << m); i++) {
int tmp = i;
int tmp1 = i;
bitset<510> b(0);
int pos = 0;
while(tmp) {
if(tmp & 1) {
b = b | a[pos];
}
tmp >>= 1;
pos++;
}
if(b.count() == n) {
ans = min(ans, count(tmp1));
}
}
if(ans != n + 1) printf("%d\n", ans);
else printf("-1\n");
}
}
L题
题意
问最大四边形的面积是多少,n < 4096
题解
建凸包,找两个点i,j(i != j)p1为i到j的三角形面积最大点,p2为j到i的三角形面积最大点。
You may not output numbers with scientific notaions. I.e., outputting 3E8 for 300000000 is not allowed.
//要用long long,不能用double
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
typedef long long ll;
const int MAX = 5e3 + 5;
struct Point{
ll x, y;
bool operator < (const Point& b) const {
return x < b.x || (x == b.x && y < b.y);
}
};
Point p[MAX];
ll inline cross(Point a, Point b, Point c ,Point d) {
return (a.x - b.x) * (c.y - d.y) - (c.x - d.x)* (a.y - b.y);
}
ll inline lenn(Point a, Point b) {
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
Point ch[MAX];
int inline andrew(Point p[], Point ch[],int n) {//安德鲁算法求凸包,返回顶点数
sort(p, p + n);
int top = 0;
for (int i = 0; i < n; i++) {
while(top > 1 && cross(ch[top], ch[top - 1], p[i], ch[top]) <= 0) --top;
ch[++top] = p[i];
}
int tmp = top;
for(int i = n - 2; i >= 0; --i) {
while((top > tmp) && cross(ch[top], ch[top - 1], p[i], ch[top]) <= 0) --top;
ch[++top] = p[i];
}
if(n > 1) top--;
return top;
}
int main() {
ios::sync_with_stdio(0);
int T;
cin >>T;
while(T--) {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;
int cnt = andrew(p, ch, n);
ch[0] = ch[cnt];
if(cnt <= 4) {
ll ans = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
for(int k = 0; k < n; k++) {
for(int q = 0; q < n; q++) {
if(i == j || i == k || i == q || j == k || j == q || k == q) continue;
ll x = cross(p[i], p[j], p[k], p[q]);
ans = max(ans, abs(x));
}
}
}
}
if(ans & 1){
cout << ans / 2 << ".5" << endl;
}
else cout << ans / 2 << endl;
}
else {
ll ans = 0;
for(int i = 0; i < cnt; i++) {
int p1 = (i + 1) % cnt, p2 = (i + 1) % cnt;
//p1,p2放在外面,否则j变化,p2要每次从头开始遍历
for(int j = (i + 2) % cnt; j != (i - 1 + cnt) % cnt; j = (j + 1) % cnt) {
if(i == j) continue;
// i -- p1 j -- p2
while(cross(ch[i], ch[p1], ch[i], ch[j]) < cross(ch[i], ch[(p1 + 1) % cnt], ch[i], ch[j])) {
if((p1 + 1) % cnt == j) break;
p1 = (p1 + 1) % cnt;
}
while(cross(ch[i], ch[j], ch[i], ch[p2]) < cross(ch[i], ch[j], ch[i], ch[(p2 + 1) % cnt])) {
if((p2 + 1) % cnt == i) break;
p2 = (p2 + 1) % cnt;
}
ll x = cross(ch[i], ch[p1], ch[i], ch[j]) + cross(ch[i], ch[j], ch[i], ch[p2]);
ans = max(ans, x);
}
}
if(ans & 1){
cout << ans / 2 << ".5" << endl;
}
else cout << ans / 2 << endl;
}
}
}
debug//错误版本
// WA掉了
//原因p1,p2可能变成同一个点,这样就变成三角形了
//下图
ll ans = 0;
cnt++;
for(int i = 0; i < cnt; i++) {
for(int j = 0; j < cnt; j++) {
if(i == j) continue;
int p1 = i + 1, p2 = j + 1;
// i -- p1 j -- p2
while(cross(ch[i], ch[p1], ch[i], ch[j]) < cross(ch[i], ch[(p1 + 1) % cnt], ch[i], ch[j])) {
if((p1 + 1) % cnt == j) break;
p1 = (p1 + 1) % cnt;
}
while(cross(ch[j], ch[i], ch[j], ch[p2]) < cross(ch[j], ch[i], ch[j], ch[(p2 + 1) % cnt])) {
if((p2 + 1) % cnt == i) break;
p2 = (p2 + 1) % cnt;
}
ll x = cross(ch[i], ch[p1], ch[i], ch[j]) + cross(ch[i], ch[j], ch[i], ch[p2]);
ans = max(ans, x);
}
}
// T
//原因 j变化,p2要每次从头开始遍历
ll ans = 0;
for(int i = 0; i < cnt; i++) {
for(int j = (i + 2) % cnt; j != (i - 1 + cnt) % cnt; j = (j + 1) % cnt) {
if(i == j) continue;
int p1 = (i + 1) % cnt, p2 = (j + 1) % cnt;
// i -- p1 j -- p2
while(cross(ch[i], ch[p1], ch[i], ch[j]) < cross(ch[i], ch[(p1 + 1) % cnt], ch[i], ch[j])) {
if((p1 + 1) % cnt == j) break;
p1 = (p1 + 1) % cnt;
}
while(cross(ch[i], ch[j], ch[i], ch[p2]) < cross(ch[i], ch[j], ch[i], ch[(p2 + 1) % cnt])) {
if((p2 + 1) % cnt == i) break;
p2 = (p2 + 1) % cnt;
}
ll x = cross(ch[i], ch[p1], ch[i], ch[j]) + cross(ch[i], ch[j], ch[i], ch[p2]);
ans = max(ans, x);
}
}
C题(水)
题意
问是否对于每三个数a[i], a[j], a[k]都存在(a[i] - a[j]) / a[k]
数据范围 3 <= n <= 50
题解
模拟
H题(水)
题意
给n,问最大的a,满足 1 n = 1 a 异 或 b + 1 b \frac{1}{n} = \frac{1}{a 异或 b} + \frac{1}{b} n1=a异或b1+b1
题解
大胆猜测,如果没有思路的话
赛场是猜出来的,猜b = a + 1
O(1)
//严谨证明
#include <iostream>
#include <cmath>
#include <cstdio>
#define ll long long
using namespace std;
const int MAX = 56;
int main() {
int n;
scanf("%d", &n);
double a[MAX];
for(int i = 0; i < n; i++) {
ll x;
scanf("%lld", &x);
ll ans = x * (x + 1);
ll res = ans ^ (x + 1);
printf("%lld\n", res);
}
}