[考试总结]noip模拟16

达成成就,一天更3篇总结。

又是一个暴力场

别问我为什么开局 \(5\) 分钟就问老师为什么 \(T3\) 没有提交的窗口。

开题读题,一路自闭到 \(T3\) ,发现 \(T3\) 可打暴力,所以一波暴力打上去,开始只有 \(30pts\)

然后转向 \(T2\) ,发现也有部分分数可以打,所以就开始打这个题目的暴力。

瞄准 \(20pts\) 部分分数,然后疯狂开始打。

打完之后也不能放弃啊,所以开始回去开 \(T1\),然后开始自闭。

给的样例手摸都出不来。。。。

自闭\(*2\)

突然思路开始涌现,发现可以把坐标系分成 \(1000\) * \(1000\),然后开始一个一个点枚举,这样的话就能骗过\(Special\;Judge\)

然后开始打。。。

然后样例都调不出来。。。

自闭\(*3\)

但是经过我的奋战,\(T1\) 终于出来了样例。。。

然后转向 \(T3\),感觉数组好像开的有点小,但是部分分数似乎也够,但还好我开打了一些。又赚了 \(20pts\)

不扯淡了

T1:

首先考虑的应该是二分做法。

然后如果打对就可以得到 \(80pts\)

然而只有土哥打对了。。。。

战神看出了正解最小生成树,然而 \(Kruskal\) 爆炸了。。。

然而还是极其强大。。。

正解就是最小生成树,然后 \(Kruskal\) 也可以过。

就是每个点连边,然后和上下边界连边。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
//#define int long long
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 0x7f7f7f,mod = (1<<30);
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	const double eps = 1e-8;
	int n,m,k;
	class xin_data{public:int x,y;}d[maxn];
	inline double getdis(double x1,double y1,double x2,double y2)
	{return std::sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));}
	inline bool equal(double x,double y)
	{
		if(abs(x - y) <= eps) return true;
		return false;
	}
	int x[maxn],y[maxn];
	double dis[maxn];
	bool vis[maxn];
	double ans = -inf * 1.0;
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>(); m = get<signed>(); k = get<signed>();
		try(i,1,k) x[i] = get<signed>(),y[i] = get<signed>(),dis[i] = (double)(m - y[i]);
		dis[k+1] = m; dis[0] = inf * 1.0;
		while(true)
		{
			register int temp = 0;
			try(i,1,k+1)if(!vis[i] and dis[i] < dis[temp]) temp = i;
			vis[temp] = true;
			ans = std::max(ans,dis[temp]);
			if(temp == k + 1) break;
			try(i,1,k) dis[i] = std::min(dis[i],getdis(x[i],y[i],x[temp],y[temp]));
			dis[k+1] = std::min(dis[k+1],y[temp] * 1.0);
		}
		printf("%0.9lf\n",ans/2.0);
		return 0;
	}
}
signed main() {return xin::main();}

T2:

要找一个极长上升序列。

然后线段树优化。。。。

老猥琐了。。

自己研究吧。。。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
//#define int long long
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 0x7f7f7f7f,mod = (1<<30);
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	int p[maxn],c[maxn];
	int n;
	int f[maxn];
	int maxx = 0;	
	class xin_segment
	{
		private:
			#define ls(fa) (fa << 1)
			#define rs(fa) (fa << 1 | 1)
			inline void up(int fa,int l,int r,int x)
			{
				register int mid = l + r >> 1;
				t[fa].mf = find(ls(fa),l,mid,l,mid,t[rs(fa)].mx);
				t[fa].f = std::min(t[ls(fa)].f,t[rs(fa)].f);
				t[fa].mx = std::max(t[ls(fa)].mx,t[rs(fa)].mx);
//				cout<<"t[fa].mx = "<<t[fa].mx<<endl;
			}
		public:
			class xin_tree{public:int mx,mf,f;}t[maxn];
			int find(int fa,int l,int r,int ql,int qr,int p)
			{
				if(t[fa].mx < p) return inf;
				if(l == r) {maxx = std::max(maxx,t[fa].mx); return t[fa].f;}
				register int mid = l + r >> 1;
				if(l == ql and r == qr)
				{
					if(t[rs(fa)].mx < p) return find(ls(fa),l,mid,ql,mid,p); maxx = std::max(maxx,t[fa].mx); //cout<<"maxx = "<<maxx<<endl;
					return std::min(t[fa].mf,find(rs(fa),mid+1,r,mid+1,qr,p));
				}
				if(qr <= mid) return find(ls(fa),l,mid,ql,qr,p);
				else if(ql > mid) return find(rs(fa),mid+1,r,ql,qr,p);
				else {maxx = 0; register int temp = find(rs(fa),mid+1,r,mid+1,qr,p);return std::min(temp,find(ls(fa),l,mid,ql,mid,maxx));}
			}
			void insert(int fa,int l,int r,int x,int p)
			{
				if(x > r or x < l) return ;
				if(l == r) {t[fa].f = f[p]; t[fa].mx = p; return;}
				register int mid = l + r >> 1;
				insert(ls(fa),l,mid,x,p); insert(rs(fa),mid+1,r,x,p);
				up(fa,l,r,x);
			}
	}t;
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>();
		try(i,1,n) p[i] = get<signed>();
		try(i,1,n) c[i] = get<signed>();
		try(i,1,(n<<2)) t.t[i].f = t.t[i].mf = inf;
		for(register int i=1;i<=(n<<2);i<<=1) t.t[i].f = t.t[i].mf = 0;
		try(i,1,n)
		{
			f[i] = t.find(1,0,n,0,p[i] - 1,0) + c[i];
			t.insert(1,0,n,p[i],i);
		}
		register int ans = inf,temp = 0;
		throw(i,n,1) if(temp < p[i]) temp = p[i],ans = std::min(ans,f[i]);
		cout<<ans<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

T3:

咱们把式子变换一下

然后发现:

\[\frac {c_u-c_v}{dis_{v,u}}=\frac {c_u-c_v}{d_v-d_u}=-\frac {c_v-c_u} {d_v-d_u} \]

然后就是一个斜率式子。

然后维护凸包,找到斜率最大的。

采用倍增的方法,然后飞快。

防止黑心出题人

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
//#define int long long
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 0x7f7f7f,mod = (1<<30);
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	class xin_edge{public:int next,ver;}edge[maxn];
	int d[maxn],fa[maxn][31],ans[maxn],c[maxn],n;
	int head[maxn],zhi = 0;
	inline void add(int x,int y) {edge[++zhi].ver = y; edge[zhi].next = head[x]; head[x] = zhi;}
	inline double getk(int x,int y) {return (double)(c[x] - c[y]) / (double)(d[y] - d[x]);}
	void dfs(int x)
	{
		register int now = fa[x][0];
		throw(i,30,0)
		{
			if(fa[now][i] <= 1) continue;
			if(getk(x,fa[now][i]) >= getk(x,fa[fa[now][i]][0])) now = fa[fa[now][i]][0]; //just jump to the best
		}
		if(now > 1 and getk(x,now) >= getk(x,fa[now][0])) now = fa[now][0];
		ans[x] = now; fa[x][0] = now;  //this method is not totally the same as before,f[x][0] is its best answer but not his father
		try(i,1,30) fa[x][i] = fa[fa[x][i-1]][i-1];
		for(register int i=head[x];i;i=edge[i].next)
		{
			register int y = edge[i].ver;
			d[y] = d[x] + 1; dfs(y);
		}
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>();
		try(i,1,n) c[i] = get<signed>();
		try(i,2,n)
		{
			fa[i][0] = get<signed>();
			add(fa[i][0],i);
		}
		d[1] = 1;
		dfs(1);
		try(i,2,n) printf("%.10lf\n",getk(i,ans[i]));
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-07-16 17:44  NP2Z  阅读(36)  评论(0编辑  收藏  举报