算法竞赛进阶指南 0x00 总结与练习

AcWing 119. 袭击

分治求平面最近点对,与模板不同的地方在于点分两类,求第一类点中与第二类点中距离最近的点对。计算时如果点为同一类,距离设置为INF即可

//#define LOCAL
#include 
using namespace std;
#define DBG printf("%d %s\n",__LINE__,__FUNCTION__)
#define CLOSE ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define abs(x) ((x) >= 0 ? (x) : -(x))
#define LF putchar('\n')
#define SP putchar(' ')
#define eb emplace_back
#define mk make_pair
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define eps 1e-6
#define ri register int
#define rl register long long
#define LL long long
#define ULL unsigned long long

template<typename T> 
void read(T &x) {x = 0;char ch = getchar();LL f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args> 
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}

const LL MOD = 1e9 + 7;
const int MAXN = 2e5 + 50;
const double inf = 1e11;

int T, n;
struct node {
	double x, y;
	int type;
	bool operator < (const node &a) const {
		return x < a.x;
	}
}po[MAXN], tmp[MAXN];

double dis(node a, node b) {
	if(a.type == b.type) {
		return inf;
	} else {
		return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
	}
}

double divt(int l, int r) {
	if(l >= r) {
		return inf;
	}
	int mid = (l + r) >> 1;
	double mid_x = po[mid].x;
	double res = min(divt(l, mid), divt(mid + 1, r));
	{
		int i = l, j = mid + 1, k = 0;
		while(i <= mid && j <= r) {
			if(po[i].y < po[j].y) {
				tmp[k++] = po[i++];
			} else {
				tmp[k++] = po[j++];
			}
		}
		while(i <= mid) {
			tmp[k++] = po[i++];
		}
		while(j <= r) {
			tmp[k++] = po[j++];
		}
		for(i = 0, j = l; i < k; ++i, ++j) {
			po[j] = tmp[i];
		}
	}
	int k = 0;
	for(ri i = l; i <= r; ++i) {
		if(po[i].x >= mid_x - res && po[i].x <= mid_x + res) {
			tmp[k++] = po[i];
		}
	}
	for(ri i = 0; i < k; ++i) {
		for(ri j = i - 1; j >= 0 && tmp[i].y - tmp[j].y < res; --j) {
			res = min(res, dis(tmp[i], tmp[j]));
		}
	}
	//printf("%.3lf\n", res);
	return res;
}

int main() {
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    read(T);
    while(T--) {
    	read(n);
    	for(ri i = 0; i < n; ++i) {
    		scanf("%lf %lf", &po[i].x, &po[i].y);
    		po[i].type = 0;
    	}
    	for(ri i = n; i < 2 * n; ++i) {
    		scanf("%lf %lf", &po[i].x, &po[i].y);
    		po[i].type = 1;
    	}
   		sort(po, po + 2 * n);
    	printf("%.3lf\n", divt(0, 2 * n - 1));
    }
    return 0;
}

AcWing 120. 防线

二分答案,单调性在于偶数+奇数为奇数,偶数+偶数为偶数。因为只存在一个奇数点,所以对整条线段做前缀和,奇数点及后面的前缀和为奇数,前面的为偶数。

//#define LOCAL
#include 
using namespace std;
#define DBG printf("%d %s\n",__LINE__,__FUNCTION__)
#define CLOSE ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define abs(x) ((x) >= 0 ? (x) : -(x))
#define LF putchar('\n')
#define SP putchar(' ')
#define eb emplace_back
#define mk make_pair
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define eps 1e-6
#define ri register int
#define rl register long long
#define LL long long
#define ULL unsigned long long

template<typename T> 
void read(T &x) {x = 0;char ch = getchar();LL f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args> 
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}

const LL MOD = 1e9 + 7;
const int MAXN = 2e5 + 50;

struct node {
	LL s, e, d;
}p[MAXN];
int T, n;

int getsum(LL k) {
	int res = 0;
	for(ri i = 1; i <= n; ++i) {
		if(k >= p[i].s) {
			if(k > p[i].e) {
				res += (p[i].e -p[i].s) / p[i].d + 1;
			} else {
				res += (k - p[i].s) / p[i].d + 1;
 			}
		}
	}
	return res;
}

bool check(LL k) {
	if(getsum(k) % 2) {
		return true;
	} else {
		return false;
	}
}

int main() {
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    read(T);
    while(T--) {
    	read(n);
    	for(ri i = 1; i <= n; ++i) {
    		read(p[i].s, p[i].e, p[i].d);
    	}
    	LL l = 0, r = 1e10;
    	if(getsum(r) % 2 == 0) {
    		printf("There's no weakness.\n");
    		continue;
    	}
    	while(l < r) {
    		LL mid = (l + r) >> 1;
    		if(check(mid)) {
    			r = mid;
    		} else {
    			l = mid + 1;
    		}
    	}
    	int ans = 0;
    	for(ri i = 1; i <= n; ++i) {
    		if(r <= p[i].e && r >= p[i].s) {
    			ans += (r - p[i].s) % p[i].d == 0 ? 1 : 0;
    		}
    	}
    	write(r, ans), LF;
    }
    return 0;
}

AcWing 125. 耍杂技的牛

临项交换证明的贪心,类似于国王游戏

//#define LOCAL
#include 
using namespace std;
#define DBG printf("%d %s\n",__LINE__,__FUNCTION__)
#define CLOSE ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define abs(x) ((x) >= 0 ? (x) : -(x))
#define LF putchar('\n')
#define SP putchar(' ')
#define eb emplace_back
#define mk make_pair
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define eps 1e-6
#define ri register int
#define rl register long long
#define LL long long
#define ULL unsigned long long

template<typename T> 
void read(T &x) {x = 0;char ch = getchar();LL f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args> 
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}

const LL MOD = 1e9 + 7;
const int MAXN = 5e4 + 50;


struct node {
	LL w, s;
	bool operator < (const node &a) const {
		return w + s < a.w + a.s;
	}
}p[MAXN];
LL n;

int main() {
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    read(n);
    for(ri i = 1; i <= n; ++i) {
    	read(p[i].w, p[i].s);
    }
    sort(p + 1, p + n + 1);
    LL now = 0, ans = -1e18;
    for(ri i = 1; i <= n; ++i) {
    	//write(p[i].w, p[i].s), LF;
    	ans = max(ans , now - p[i].s);
    	now += p[i].w;
    }
    write(ans), LF;
    return 0;
}

AcWing 127. 任务

贪心,策略为以 x x x从大到小的顺序考虑每一个任务,如果能匹配机器,则从能匹配的机器中选择机器 y y y最小的一个。贪心的证明思路类似于0x00贪心专题中防晒一题。寻找 y y y的时候用multiset以保证时间复杂度

//#define LOCAL
#include 
using namespace std;
#define DBG printf("%d %s\n",__LINE__,__FUNCTION__)
#define CLOSE ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define abs(x) ((x) >= 0 ? (x) : -(x))
#define LF putchar('\n')
#define SP putchar(' ')
#define eb emplace_back
#define mk make_pair
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define eps 1e-6
#define ri register int
#define rl register long long
#define LL long long
#define ULL unsigned long long

template<typename T> 
void read(T &x) {x = 0;char ch = getchar();LL f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args> 
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}

const LL MOD = 1e9 + 7;
const int MAXN = 1e5 + 50;

struct node {
	int x, y;
	bool operator < (const node &a) const {
		if(x == a.x) {
			return y < a.y;
		}
		return x < a.x;
	}
}p[MAXN], q[MAXN];

int n, m;

int main() {
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    while(cin >> n >> m) {
    	for(ri i = 1; i <= n; ++i) {
    		read(p[i].x, p[i].y);
    	}
    	for(ri i = 1; i <= m; ++i) {
    		read(q[i].x, q[i].y);
    	}
    	sort(p + 1, p + n + 1);
    	sort(q + 1, q + m + 1);
    	LL ans = 0, cnt = 0;
    	multiset<int>se;
    	for(ri i = m, j = n; i >= 1; --i) {
    		while(j >= 1 && p[j].x >= q[i].x) {
    			se.insert(p[j].y), --j;
    		}
    		auto it = se.lower_bound(q[i].y);
    		if(it != se.end()) {
    			++cnt;
    			ans += 500 * q[i].x + 2 * q[i].y;
    			se.erase(it);
    		}
    	}
    	cout << cnt << ' ' << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(算法竞赛进阶指南)