恩欧挨批模拟试题-18

水博客太快乐了

RT

考场

先看 \(T1\) ,乍一看貌似是计算几何,得搞个凸包,手膜了一下,发现不对,想了各种特判,都不对,又想到时间与速度是成反比的,于是把所有点变成原点的倒数,再搞凸包,又手膜了一下,发现还不对。。。(可能是我手膜错了。。。

于是去看 \(T2\) ,发现是裸的高斯消元。。。

再看 \(T3\) ,真没啥思路。。。

然后写了两个小时高斯消元,就这都没调出来。。。。(实际上是一个特别 \(NT\) 的错误,让巨佬帮忙一下就看出来了。。。

然后感觉时间不够,放弃 \(T2\) 去写 \(T1\) ,写了奇奇怪怪的和斜率有关的东西,感觉能骗不少分。。。

分数

预估 : \(t1\) \(80pts\) \(+\) \(t2\) \(0pts\) \(+\) \(t3\) \(0pts\) \(=\) \(80pts\)
实际 : \(t1\) \(70pts\) \(+\) \(t2\) \(0pts\) \(+\) \(t3\) \(0pts\) \(=\) \(70pts\)

越来越菜了。。。

题解

A. 导弹袭击

考完下来看题解,发现 \(t1\) 就是把每个点变成倒数,再维护一个下凸包。。。

血亏。。。
不过维护的时候要注意可能会有重点,还有某两个点的横坐标或纵坐标相等时需要特判。。。

并没有想象中的好写。。

code

代码中并没有将每个点变成倒数,而是在计算两点间斜率时直接按照倒数来计算

#include<bits/stdc++.h>
using namespace std;
#define double long double
const int N=3e5+10;
inline int read(){
	int f=1, x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
	return f*x;
}
int n;
struct NODE{
	double x, y;
	int id;
	friend bool operator < (const NODE &a, const NODE &b) { return a.x==b.x ? a.y > b.y : a.x > b.x; }
}d[N];
double k1[N];
int stk[N], top;
bool vis[N], ans[N];
double k(int a, int b) { return d[a].x*d[b].x*(d[a].y-d[b].y)/(d[a].y*d[b].y*(d[a].x-d[b].x)); }
int main(void){
	n=read();
	for(int i=1; i<=n; ++i)
		d[i]=(NODE){ read(), read(), i};
	sort(d+1, d+1+n);
	int maxn=0;
	for(int i=1; i<=n; ++i){
		if(d[i].y<=maxn) vis[i]=1;
		else maxn=d[i].y;
	}
	stk[++top]=1;
	for(int i=2; i<=n; ++i){
		if(vis[i]||k(stk[top], i)>0) continue;
		while(top>1&&k(stk[top], i)<k(stk[top-1], stk[top])) top--;
		stk[++top]=i;
	}
	for(int i=1; i<=top; ++i){
		ans[d[stk[i]].id]=1;
		for(int j=stk[i]+1; j<=n&&d[stk[i]].x==d[j].x&&d[stk[i]].y==d[j].y; ++j) ans[d[j].id]=1;
	}
	for(int i=1; i<=n; ++i) if(ans[i]) printf("%d ", i);
	printf("\n");
	return 0;
}

B. 炼金术士的疑惑

裸的高斯消元。。。
把给出的线性方程进行高斯消元,高斯消元的同时对给出的目标方程进行相同的操作,因为保证有解,所以最后目标方程的系数一定会全部被消成 \(0\) ,而答案就是该方程的值的相反数。。。
如何证明??
设开始时目标方程的值为 \(h\) ,结束时变为 \(h+b\) ,因为方程左边为 \(0\) 所以 \(h+b=0\) ,既 \(h=-b\)

高斯消元的模板不太熟练了,居然两个小时那么一个简单的错误都没有调出来。。。

小错误:找到每一个元的最大系数后,除法时没有赋值,而是直接除。。。

code
#include<bits/stdc++.h>
using namespace std;
const int N=210, INF=0x7fffffff;
const double ops=1e-6;
int n;
string c[N][N], ul;
int num[N], tot=0;
double a[N][N], b[N], a1[N], ans;
map<string, int> m;
inline void solve(){
	for(int i=1; i<=tot; ++i){
		int id=0;
		for(int j=i; j<n; ++j) if(fabs(a[j][i])>fabs(a[id][i])) id=j;
		if(!id) continue;
		if(i!=id) for(int j=1; j<=tot; ++j) swap(a[i][j], a[id][j]);
		if(i!=id) swap(b[i], b[id]);
		double ul1=a[i][i];
		for(int j=1; j<=tot; ++j)
			a[i][j]/=ul1;
		b[i]/=ul1;
		for(int j=1; j<=n; ++j){
			if(i==j) continue;
			double ul=a[j][i];
			for(int k=1; k<=tot; ++k) a[j][k]-=ul*a[i][k];
			b[j]-=ul*b[i];
		}
	}
	if(b[n]-ops<0&&b[n]+ops>0) printf("0.0\n");
	else printf("%.1lf\n", -b[n]);
}
int main(void){
	scanf("%d", &n); ++n;
	for(int i=1; i<=n; ++i){
		int j=1;
		for(j=1; j; ++j){
			scanf("%lf", &a[i][j]);
			cin>>c[i][j]; cin>>ul;
			if(ul[0]=='=') break;
		}
		for(++j; j; ++j){
			scanf("%lf", &a[i][j]); cin>>c[i][j];
			cin>>ul; a[i][j]=-a[i][j];
			if(ul[1]=='=') break;
		}
		num[i]=j; scanf("%lf", &b[i]);
	}
	for(int i=1; i<=n; ++i) for(int j=1; j<=num[i]; ++j)
		if(m[c[i][j]]==0) m[c[i][j]]=++tot;
	for(int i=1; i<=n; ++i){
		memset(a1, 0, sizeof a1);
		for(int j=1; j<=num[i]; ++j) a1[m[c[i][j]]]=a[i][j];
		for(int j=1; j<=tot; ++j) a[i][j]=a1[j];
	}
	solve();
	return 0;
}

C. 老司机的狂欢

貌似是本场比赛最难的题。。。

确实没什么思路。。。。

首先二分时间很容易想到,然后就是怎么 \(check\) 了,考虑先将所有点按其初始坐标排序,然后算出每个点的终点坐标,求 \(LIS\) 即可。

然后看第二小问怎么求,要求出字典序最小的方案,考虑每个点可以由哪些节点更新过来,找这些节点里字典序最小的即可。。。
\(LIS\) 的过程可以被看作一棵树,假设某个点可以被 \(i, j\) 更新得到,则只需要找到 \(i, j, lca(i,j)\) 路径上的最小编号进行比较即可,可以用倍增实现。

代码并不是很好写。。。。

code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f first
#define s second
const int N=1e5+10;
inline int read(){
	int f=1, x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
	return f*x;
}
int n, k;
struct node{
	long long x, a;
	int id;
	friend bool operator < (const node &x, const node &y) { return x.x < y.x; }
}d[N];
long long p[N], b[N];
#define lb(x) x&-x
class fakeTRE{
private :
	int a[N], fa[N][20], minn[N][20], rec[N];
	pair<int, int > t[N];
	inline bool getmin(pair<int, int > a, pair<int, int > b){
		if(a.f!=b.f) return a.f<b.f;
		int mina=a.s, minb=b.s, u=a.s, v=b.s;
		for(int i=19; ~i; --i)
			if(fa[u][i]!=fa[v][i]){
				mina=min(mina, minn[u][i]);
				minb=min(minb, minn[v][i]);
				u=fa[u][i], v=fa[v][i];
			}
		return mina>minb;
	}
public :
	inline void clear() { memset(a, 0, sizeof a); }
	inline void add(int p, int x) { for(; p<=n; p+=lb(p)) a[p]=max(a[p], x); }
	inline void Tadd(int p, pair<int, int > x) {	for(; p<=n; p+=lb(p)) if(getmin(t[p], x)) t[p]=x; }
	inline int que(int p) { int ans=0; for(; p; p-=lb(p)) ans=max(ans, a[p]); return ans; }
	inline pair<int, int > Tque(int p){
		pair<int, int > ans=make_pair(0, 0);
		for(; p; p-=lb(p))
			if(getmin(ans, t[p])) ans=t[p];
		return ans;
	}
	inline void built(int x, int f){
		fa[x][0]=minn[x][0]=f;
		for(int i=1; i<=19; ++i){
			fa[x][i]=fa[fa[x][i-1]][i-1];
			minn[x][i]=min(minn[x][i-1], minn[fa[x][i-1]][i-1]);
		}
	}
	inline void print(){
		int now=Tque(n).s;
		for(int i=1; i<=k; ++i)
			rec[i]=now, now=fa[now][0];
		sort(rec+1, rec+1+k);
		for(int i=1; i<=k; ++i) printf("%lld\n", rec[i]);
	}
}t;
#undef lb
int check(int t1){
	t.clear();
	for(int i=1; i<=n; ++i) b[i]=p[i]=(d[i].x<<1)+d[i].a*t1*t1;
	sort(b+1, b+1+n); int len=unique(b+1, b+1+n)-b-1;
	for(int i=1; i<=n; ++i){
		p[i]=lower_bound(b+1, b+1+len, p[i])-b;
		t.add(p[i], t.que(p[i]-1)+1);
	}
	return t.que(n);
}
signed main(void){
	n=read(); k=read();
	for(int i=1; i<=n; ++i) d[i]=(node){ read(), read(), i};
	sort(d+1, d+1+n);
	int l=0, r=86400, ul;
	while(l<r){
		int mid=(l+r+1)>>1;
		ul=check(mid);
		if(ul>=k) l=mid;
		else r=mid-1;
	}
	printf("%lld\n", l); ul=check(l);
	if(ul>k) { printf("-1\n"); return 0; }
	for(int i=1; i<=n; ++i){
		pair<int, int > now=t.Tque(p[i]-1);
		t.built(d[i].id, now.s);
		t.Tadd(p[i], make_pair(now.f+1, d[i].id));
	}
	t.print();
	return 0;
}
posted @ 2021-07-18 12:13  Cyber_Tree  阅读(30)  评论(0编辑  收藏  举报