T1
Description
尤里背叛了苏维埃联盟!尤里具有心灵控制的能力,可以控制我方的士兵攻击同伴。为了避免这种情况,斯大林同志要求你合理地排兵布阵,使得没有两个士兵可以互相攻击。在这个问题里,你可以认为士兵的攻击范围类似于国际象棋中的马。也即,位置为(x,y)(x,y)的士兵可以攻击位置为(x±2,y±1)(x±2,y±1)或(x±1,y±2)(x±1,y±2)的士兵。请计算:在 N*M 的棋盘上最多能 放置多少个士兵。(当然,两个士兵不能在同一个位置)
设
发现当 的时候交叉放一定最优
的时候都可以放
的时候 的正方形交替放最优
然后就做完了
Codes
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void File() {
freopen("psycho.in", "r", stdin);
freopen("psycho.out", "w", stdout);
}
void Solve() {
int T, n, m;
for(scanf("%d", &T); T -- ; ) {
scanf("%d%d", &n, &m);
if(n > m) swap(n, m);
if(n == 1) {printf("%d\n", m); continue;}
if(n == 2) {printf("%d\n", 4 * (((m / 2) + 1) / 2) + ((!((m / 2) & 1)) & (m & 1)) * 2); continue;}
int n1 = n / 2, n2 = n - n1, m1 = m / 2, m2 = m - m1;
printf("%lld\n", (ll)m2 * n2 + (ll)m1 * n1);
}
}
int main() {
//File();
Solve();
return 0;
}
T2
Description
“我是超级大沙茶”—— MatoNo1MatoNo1
为了证明自己是一个超级大沙茶,MatoMato 神犇决定展示自己对叉(十字型)有多么的了解。
MatoMato 神犇有一个平面直角坐标系,上面有一些线段,保证这些线段至少与一条坐标轴平行。MatoMato 神犇需要指出,这些线段构成的最大的十字型有多大。
称一个图形为大小为 RR(RR 为正整数)的十字型,当且仅当,这个图形具有一个中心点,它存在于某一条线段上,并且由该点向上下左右延伸出的长度为 RR 的线段都被已有的线段 覆盖。
你可以假定:没有两条共线的线段具有公共点,没有重合的线段。
因为题目保证数据随机
那么答案显然很容易达到
直接 暴力加上最优性剪枝就过了
Codes
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, ch, cs, ans;
struct node {
int _x1, _y1, _x2, _y2;
bool operator < (const node &T) const {
return _x1 < T._x1;
}
}heng[N], shu[N], tmp;
void File() {
freopen("cross.in", "r", stdin);
freopen("cross.out", "w", stdout);
}
int read() {
int _ = 0, __ = getchar(), ___ = 1;
for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
return _ * ___;
}
void Solve() {
int _x1, _x2, _y1, _y2, l, r; n = read();
for(int i = 1; i <= n; ++ i) {
_x1 = read(), _y1 = read(), _x2 = read(), _y2 = read();
if(_x1 > _x2) swap(_x1, _x2);
if(_y1 > _y2) swap(_y1, _y2);
if(_x1 == _x2) shu[++ cs] = node{_x1, _y1, _x2, _y2};
else heng[++ ch] = node{_x1, _y2, _x2, _y2};
}
if(!cs || !ch) return (void)puts("Human intelligence is really terrible");
sort(shu + 1, shu + cs + 1);
for(int i = 1; i <= ch; ++ i) {
tmp._x1 = heng[i]._x1; l = lower_bound(shu + 1, shu + cs + 1, tmp) - shu;
tmp._x1 = heng[i]._x2; r = upper_bound(shu + 1, shu + cs + 1, tmp) - shu;
//cout << l << ' ' << r << endl;
int len = (heng[i]._x2 - heng[i]._x1) / 2;
for(int j = l; j < r; ++ j) {
if(ans >= len) break;
if(heng[i]._x1 <= shu[j]._x1 && shu[j]._x1 <= heng[i]._x2)
if(shu[j]._y1 <= heng[i]._y1 && heng[i]._y1 <= shu[j]._y2) {
int th = min(heng[i]._y1 - shu[j]._y1, shu[j]._y2 - heng[i]._y1);
int ts = min(shu[j]._x1 - heng[i]._x1, heng[i]._x2 - shu[j]._x1);
ans = max(ans, min(th, ts));
}
}
}
if(ans) printf("%d\n", ans);
else puts("Human intelligence is really terrible");
}
int main() {
// File();
Solve();
return 0;
}
来考虑一下数据不随机怎么做
我们发现这个答案是具有单调性的
意思是存在大十字架就存在小十字架
那么我们二分十字架的
每次找到长度大于等于 的线段
把他们两端删掉 即线段
这样子如果线段存在交集就是合法的
对于线段求交我们可以用扫描线法
每次扫到线段起点就加入,线段终点就删除
遇到竖着的线段就查询区间内是否存在横着的线段
这些操作可以用 实现
复杂度
Codes
#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 10;
int n, ch, cs, cnt;
struct Seg {
int x, y, _y, len;
}H[N], S[N];
struct node {
int id, pos, L, R;
bool operator < (const node &T) const {
return pos == T.pos ? id < T.id : pos < T.pos;
}
}tmp[N];
multiset<int> T;
bool check(int now) {
for(int i = 1; i <= ch; ++ i)
if(H[i].len >= now * 2)
tmp[++ cnt] = node{1, H[i].y + now, H[i].x, 0},
tmp[++ cnt] = node{3, H[i]._y - now, H[i].x, 0};
for(int i = 1; i <= cs; ++ i)
if(S[i].len >= now * 2)
tmp[++ cnt] = node{2, S[i].x, S[i].y + now, S[i]._y - now};
sort(tmp + 1, tmp + cnt + 1);
for(int i = 1; i <= cnt; ++ i) {
if(tmp[i].id == 1) T.insert(tmp[i].L);
if(tmp[i].id == 3) T.erase(T.find(tmp[i].L));
if(tmp[i].id == 2 && T.upper_bound(tmp[i].R) != T.lower_bound(tmp[i].L)) return true;
}
return false;
}
int main() {
#ifdef ylsakioi
freopen("cross.in", "r", stdin);
freopen("cross.out", "w", stdout);
#endif
int x, _x, y, _y; scanf("%d", &n);
for(int i = 1; i <= n; ++ i) {
scanf("%d%d%d%d", &x, &y, &_x, &_y);
if(x > _x) swap(x, _x); if(y > _y) swap(y, _y);
if(x == _x) S[++ cs] = Seg{x, y, _y, _y - y};
if(y == _y) H[++ ch] = Seg{y, x, _x, _x - x};
}
int L = 0, R = 1e9, ans = 0;
while(cnt = 0, T.clear(), L <= R) {
int mid = (L + R) >> 1;
if(check(mid)) ans = mid, L = mid + 1;
else R = mid - 1;
}
if(ans) printf("%d\n", ans);
else puts("Human intelligence is really terrible");
return 0;
}
T2
Description
从前有一个 RudyRudy。
从前还有一个网格图。
RudyRudy 喜欢爆炸。
RudyRudy 偶尔会炸掉网格图中的一条边(u,v)(u,v)。之后他会尝试从 uu 走到 vv。
如果他成功地从 uu 走到 vv,他会很高兴;否则他会找人打架。
从第二次爆炸开始,根据 RudyRudy 此时心情的不同,RudyRudy 会炸掉不同的边。
你被要求编写一个程序,对于每次爆炸,给出此时 RudyRudy 是否还能从 uu 到 vv。
把网格图的点变成格子
删一条边相当于让两个格子联通
如果两个格子在删这条边前就联通那就无解了
否则就有解 把格子外面也当做一个大格子就可以了
用并查集维护即可
Codes
#include<bits/stdc++.h>
using namespace std;
const int N = 500 + 10;
int flag, fa[N * N], n, q;
void File() {
freopen("babystep.in", "r", stdin);
freopen("babystep.out", "w", stdout);
}
int read() {
int _ = 0, __ = getchar(), ___ = 1;
for(; !isdigit(__); __ = getchar()) if(__ == '-') __ = -1;
for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
return _ * ___;
}
int find(int x) {
return fa[x] = x == fa[x] ? x : find(fa[x]);
}
bool merge(int x, int y) {
//cout << x << ' ' << y << endl;
x = find(x), y = find(y);
if(x == y) return false;
return fa[x] = y, true;
}
void get_flag(int _x1, int _y1, int _x2, int _y2) {
//cout << _x1 << ' ' << _y1 << ' ' << _x2 << ' ' << _y2 << endl;
if(_x1 == _x2 && _x1 == 1) flag = merge((n - 1) * (n - 1) + 1, _y1);
else if(_x1 == _x2 && _x1 == n) flag = merge((n - 1) * (n - 1) + 1, (n - 1) * (n - 2) + _y1);
else if(_y1 == _y2 && _y1 == 1) flag = merge((n - 1) * (n - 1) + 1, (_x1 - 1) * (n - 1) + 1);
else if(_y1 == _y2 && _y2 == n) flag = merge((n - 1) * (n - 1) + 1, _x1 * (n - 1));
else if(_x1 == _x2) flag = merge((n - 1) * (_x1 - 2) + _y1, (n - 1) * (_x1 - 1) + _y1);
else if(_y1 == _y2) flag = merge((n - 1) * (_x1 - 1) + _y1 - 1, (n - 1) * (_x1 - 1) + _y2);
}
void Solve() {
int _x1, _y1, _x2, _y2;
n = read(), q = read();
for(int i = 1; i <= n * n; ++ i) fa[i] = i;
_x1 = read(), _y1 = read(), _x2 = read(), _y2 = read();
if(_x1 > _x2) swap(_x1, _x2); if(_y1 > _y2) swap(_y1, _y2);
get_flag(_x1, _y1, _x2, _y2); puts(flag ? "HAHA" : "DAJIA");
for(int cas = 1; cas < q; ++ cas) {
if(flag) _x1 = read(), _y1 = read(), _x2 = read(), _y2 = read(), read(), read(), read(), read();
else read(), read(), read(), read(), _x1 = read(), _y1 = read(), _x2 = read(), _y2 = read();
if(_x1 > _x2) swap(_x1, _x2); if(_y1 > _y2) swap(_y1, _y2);
get_flag(_x1, _y1, _x2, _y2); puts(flag ? "HAHA" : "DAJIA");
}
}
int main() {
Solve();
return 0;
}
今天又炸飞了… 吊打
自己还是太菜了