【计几】杂题
作者:互联网
文章目录
- POJ3304 Segments【从结果出发,反推解的存在情况】
- [HOJ-Super Shuttle Super Shuttle](https://acm.hunnu.edu.cn/#/problems/11563)
- [第 45 届 ICPC 昆明 - Mr. Main and Windmills](https://ac.nowcoder.com/acm/contest/14055/J)【从状态变化点(反转点)出发,反推解的转移情况】
- [2021 icpc 网络赛第二场 Nearest Point](https://pintia.cn/problem-sets/1441745686294945792/problems/1441745856154955780)【从状态变化角度(反转角度)出发,反推解的转移情况】
- [河南省第十三届省赛 Dance with a stick](https://ac.nowcoder.com/acm/contest/17148/E)
- ACM-ICPC 2018 徐州赛区网络预赛 [Trace](https://vjudge.ppsucxtt.cn/problem/计蒜客-41185)
POJ3304 Segments【从结果出发,反推解的存在情况】
题意:问是否存在一条直线经过给定的n条线段(非规范相交)。
思路:这道题要先从结果出发,发现任意解都可以转化为经过两个端点的解,则可以从此出发。
题解:POJ3304
代码:没有过,以后更。
HOJ-Super Shuttle Super Shuttle
题意:给一个定点和一堆圆,请你画一个过定点的圆,使得它与尽可能多的圆相交。
思路:与上题大同小异。
题解:【HUNNU11563】Super Shuttle(圆的反演)(扫描线)
第 45 届 ICPC 昆明 - Mr. Main and Windmills【从状态变化点(反转点)出发,反推解的转移情况】
思路:
-
如果我们直接从乘客的路径上考虑,路径是连续的,很难找到答案。
-
如果我们从反转点考虑,会发现只有在反转点,排名才会变化,这是离散的。因此n^2预处理所有反转点,O(1)查询即可。
题解:Mr. Main and Windmills (2020icpc昆明 线段相交)
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
const int N=1100;
const double eps = 1e-9;
const double pi = acos(-1);
int dcmp(double x, double y){
if(fabs(x - y) < eps) return 0;
if(x < y) return -1;
return 1;
}
int sign(double x){
if(fabs(x) < eps) return 0;
if(x < 0) return -1;
return 1;
}
struct point{
double x, y;
bool operator == (const point a) const {
return !dcmp(x, a.x) && !dcmp(y, a.y);
}
};
point operator + (point a, point b) { return {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) { return {a.x * b, a.y * b}; }
point operator / (point a, double b) { return {a.x / b, a.y / b}; }
double length(point a) { return sqrt(a.x * a.x + a.y * a.y); }
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }
double area(point a, point b, point c) { return cross(b - a, c - a); }
double project(point a, point b, point c) { return dot(b - a, c - a) / length(b - a); }
double angle(point a) { return atan2(a.y, a.x); }
point rotate(point a, double rad) { return {a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad)}; }
point norm(point a) { return a / length(a); }
double get_dis(point a, point b) { return length(a - b); }
point get_line_intersection(point p, point v, point q, point w){
point u = p - q;
double t = cross(w, u) / cross(v, w);
return p + v * t;
}
bool on_segment(point a, point b, point c){
return sign(dot(c - a, c - b)) < 0;
}
point st, ed;
bool operator < (const point a, const point b){
double A = get_dis(a, st), B = get_dis(b, st);
return A < B;
}
point P[N];
point inter[N][N];
int cnt[N];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
scanf("%lf %lf %lf %lf", &st.x, &st.y, &ed.x, &ed.y);
for(int i=1; i<=n; i++) scanf("%lf %lf", &P[i].x, &P[i].y);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
if(i != j)
{
point now = get_line_intersection(st, ed - st, P[i], P[j] - P[i]);
if(on_segment(st, ed, now)) inter[i][++cnt[i]] = now;
}
sort(inter[i] + 1, inter[i] + cnt[i] + 1);
}
int id, k;
while(m--)
{
scanf("%d %d", &id, &k);
if(k > cnt[id]) printf("-1\n");
else{
point ans = inter[id][k];
printf("%.7f %.7f\n", ans.x, ans.y);
}
}
system("pause");
return 0;
}
2021 icpc 网络赛第二场 Nearest Point【从状态变化角度(反转角度)出发,反推解的转移情况】
思路:
-
和上一题一样。如果我们直接从360°的角度考虑,角度是连续的,很难找到答案。
-
如果我们从反转角度考虑,会发现只有在反转角度,最近点才会变化,这是离散的。因此对于每个点i,找出所有反转角度,取中点考虑即可。
踩坑:
-
1 . find函数里旋转后的点要把i点剔除,否则返回的最近点编号可能为本身。
-
2 . 对于样例三,我原先写的代码在vscode和pta clang++可以输出正确答案,在devc++ 和 pta g++就输出不了正确答案。主要在divi[cnt++] = divi[cnt - 1] + pi; 这一句话,在devc++是先++,后再调用cnt。修改之后在devc++就可以输出正确答案。
-
貌似devc++使用的是g++,vscode使用的是clang++。反正以后不要用会受到编译器差异影响的语句。
可优化:以下代码时间为1000ms左右,群友写的是80ms左右。
群友题解:The 2021 ICPC Asia Regionals Online Contest (II)
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
const int N=60;
const double eps = 1e-11;
const double pi = acos(-1);
int dcmp(double x, double y){
if(fabs(x - y) < eps) return 0;
if(x < y) return -1;
return 1;
}
int sign(double x){
if(fabs(x) < eps) return 0;
if(x < 0) return -1;
return 1;
}
struct point{
double x, y;
int id;
bool operator == (const point a) const {
return !dcmp(x, a.x) && !dcmp(y, a.y);
}
};
point operator + (point a, point b) { return {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) { return {a.x * b, a.y * b}; }
point operator / (point a, double b) { return {a.x / b, a.y / b}; }
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }
double angle(point a) { return atan2(a.y, a.x); }
point rotate(point a, double rad) { return {a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad)}; }
point P[N];
point tmp[N];
double divi[N * N * 4];
int cnt;
double ans[N][N];
void add(point v)
{
if(v.x < 0) v.x = -v.x, v.y = -v.y;
divi[cnt++] = pi / 2 - angle(v);
divi[cnt] = divi[cnt - 1] + pi, cnt++; // 原句是 divi[cnt++] = divi[cnt - 1] + pi;
}
double idx;
bool cmp(const point a, const point b){
double A = fabs(a.x - idx), B = fabs(b.x - idx);
if(dcmp(A, B)) return dcmp(A, B) < 0;
return a.id < b.id;
}
int n;
int find(double rad, int i)
{
int pos = 0;
for(int j=0; j<n; j++)
if(j != i)
tmp[pos] = rotate(P[j], rad), tmp[pos++].id = j;
idx = rotate(P[i], rad).x;
sort(tmp, tmp + pos, cmp);
return tmp[0].id;
}
int main()
{
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%lf %lf", &P[i].x, &P[i].y);
for(int i=0; i<n; i++)
{
cnt = 0;
divi[cnt++] = 0;
divi[cnt++] = pi * 2;
for(int j=0; j<n; j++)
if(i != j)
for(int k=j + 1; k<n; k++)
if(k != i)
{
if(sign(cross(P[j] - P[i], P[k] - P[i]))== 0) continue;//不要也可以ac
add(P[k] - P[j]);
add((P[k] + P[j]) / 2 - P[i]);
}
sort(divi, divi + cnt, less<double> ());
for(int j=1; j<cnt; j++){
double mid = (divi[j] + divi[j - 1]) / 2;
ans[i][find(mid, i)] += (divi[j] - divi[j - 1]);
}
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
printf("%.11f ", ans[i][j] / pi / 2);
printf("\n");
}
system("pause");
return 0;
}
河南省第十三届省赛 Dance with a stick
思路:
- 发现棍子的左右点的个数是不变的。存在解的话排序找中点即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
pair<int,int>q[N];
int main()
{
int n; scanf("%d", & n);
for(int i=0 ; i < n; i++) scanf("%d %d",&q[i].first, &q[i].second);
sort(q, q + n);
if(n == 1){
printf("Yes\n%d %d 0 1",q[0].first, q[0].second);
// system("pause");
return 0;
}
if((n & 1) == 0){
printf("No\n");
// system("pause");
return 0;
}
int mid = (n - 1)/2;
printf("Yes\n");
printf("%d %d ",q[mid].first, q[mid].second);
if(q[mid - 1].first == q[mid].first || q[mid + 1].first == q[mid].first) printf("-1 300000000");
else printf("0 1");
// system("pause");
return 0;
}
ACM-ICPC 2018 徐州赛区网络预赛 Trace
ps:不用线段树就行,set维护即可。
AC代码:
#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=5e4+10;
LL x[N], y[N];
int n;
LL get_ans(LL * x)
{
LL res = 0;
set<LL>st;
st.insert(0);
for(int i=n-1; i>=0; i--)
{
auto it = st.lower_bound(x[i]);
it--;
res += x[i] - *(it);
st.insert(x[i]);
}
return res;
}
int main()
{
scanf("%d",&n);
for(int i=0; i<n; i++) scanf("%lld %lld", &x[i], &y[i]);
LL ans = get_ans(x) + get_ans(y);
printf("%lld", ans);
system("pause");
return 0;
}
标签:计几,cnt,return,point,int,double,include,杂题 来源: https://blog.csdn.net/weixin_51948235/article/details/120627052