noip模拟18[导弹袭击·炼金术士的疑惑·老司机的狂欢]

noip模拟18 solutions

分数还是可以,但是只是暴力分,真正的正解我理解了好久

。。。下一场都考完了我才改完

T1 导弹袭击

呵呵考试的时候直接维护的范围,比\(O(n^2)\)小那么一点点,但是根本过不了

我确实想到了是斜率优化,没有画图,然后不知道咋弄了就放弃了

考完改题的时候,我一直想着昨天的那个二分弹栈,然后手动给我的单调栈加了个log

hhh,然后看完std才改过来

我们让\(\frac{1}{a},\frac{1}{b}\)为他们的坐标,然后维护一个左下凸包就好了

推完式子发现,我们完全不需要AB,而且只有斜率为负的时候才有效,然后就维护就好了

最最最最重要的,要去重,然后绝对不可能的就不要往栈中放了,直接走人就好了

还有一个,千万不要用\(\frac{1}{a},\frac{1}{b}\)当作他们的坐标来计算,精度太小,根本卡不过

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ld long double
const int N=3e5+5;
int n;
struct POT{
	ld x,y;
	vector<int> id;
	bool operator < (POT a)const{
		if(a.x!=x)return a.x<x;
		return a.y<y;
	}
}sca[N];
int sta[N],top;
ld k[N],mx,my;
bool vis[N];
ld K(POT a,POT b){
	return b.x*a.x*(b.y-a.y)/b.y/a.y/(b.x-a.x);
}
signed main(){
	scanf("%d",&n);
	for(re i=1;i<=n;i++){
		scanf("%Lf%Lf",&sca[i].x,&sca[i].y);
		sca[i].id.push_back(i);
		if(my<sca[i].y)mx=sca[i].x,my=sca[i].y;
		if(my==sca[i].y&&mx<sca[i].x)mx=sca[i].x,my=sca[i].y;
	}
	sort(sca+1,sca+n+1);
	sta[top=1]=1;
	for(re i=2;i<=n;i++){
		if(mx>sca[i].x)break;
		if(sca[i].x==sca[sta[top]].x){
			if(sca[i].y==sca[sta[top]].y)
				sca[sta[top]].id.push_back(sca[i].id[0]);
			continue;
		}
		while(top>1&&k[top]>K(sca[sta[top]],sca[i]))top--;
		sta[++top]=i;k[top]=K(sca[sta[top-1]],sca[i]);
	}
	for(re i=1;i<=top;i++)
		for(re j=0;j<sca[sta[i]].id.size();j++)
			vis[sca[sta[i]].id[j]]=true;
	for(re i=1;i<=n;i++)if(vis[i])printf("%d ",i);
}

·

T2 炼金术士的疑惑

这个就是一个变相的高斯消元

然后,我们很容易就搞到一个正常的高斯消元,把方程式竖起来

但是随后我们就发现有可能有多组解,然后导致我们求不出来,我在考场上就止步于此了

所以我们就不需要求每一个解了

我们不需要把方程式竖起来,就直接向下消,题目保证有解,所以最后要求的方程式的所有系数都会消成0

那么此时的n+1位就是答案的负数

AC_code


#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=250;
int n;
map<string,int> mp;
double jz[N][N],hb[N];
int cnt;
double x[N],ans;
signed main(){
	//string a;cin>>a;cout<<a;
	scanf("%d",&n);
	for(re i=1;i<=n+1;i++){
		int typ=0;
		while(1){
			double x;
			string c;
			cin>>x>>c;
			//cout<<c<<" "<<mp[c]<<endl;
			if(!mp[c])mp[c]=++cnt;
			if(typ)x=-x;
			jz[i][mp[c]]+=x;
			cin>>c;
			if(c[0]=='=')typ=1;
			if(c[0]=='H'&&c[1]=='='){
				char a[3];
				if(i==n+1){
					cin>>c;
					//cout<<c<<endl;
					break;
				}
				cin>>hb[i];
				//cin>>c;
				break;
			}
		}
	}
	/*for(re k=1;k<=cnt;k++){
		for(re i=1;i<=n+1;i++){
			cout<<jz[k][i]<<" ";
		}
		cout<<hb[k]<<endl;
	}*/
	for(re i=1;i<=n;i++)jz[i][cnt+1]=hb[i];
	int h,z=1;
	for(h=1;h<=n&&z<=cnt;h++,z++){
		int maxn=h;
		for(re i=h+1;i<=n;i++)
			if(fabs(jz[i][z])>fabs(jz[maxn][z]))
				maxn=i;
		if(maxn!=h)
			for(re i=1;i<=cnt+1;i++)
				swap(jz[maxn][i],jz[h][i]);
		if(fabs(jz[h][z])==0){
			h--;continue;
		}
		for(re i=h+1;i<=n;i++){
			if(fabs(jz[i][z])==0)continue;
			double t=jz[i][z]/jz[h][z];
			for(re j=z;j<=cnt+1;j++)jz[i][j]-=jz[h][j]*t;
		}
		double t=jz[n+1][z]/jz[h][z];ans+=t*hb[h];
		//cout<<h<<" "<<t<<" "<<hb[h]<<endl;
		for(re j=z;j<=cnt+1;j++)jz[n+1][j]-=jz[h][j]*t;
	}
	//cout<<h<<" "<<z<<endl;
	/*for(re i=h;i>=1;i--){
		double t=jz[i][n+1];
		for(re j=z;j>i;j--)
			t-=jz[i][j]*x[j];
		x[i]=t/jz[i][i];
	}*/
	/*for(re i=1;i<=n;i++){
		ans+=x[i]*hb[i];
	}*/
	
	printf("%.1lf",(jz[n+1][cnt+1]==0)?0:-jz[n+1][cnt+1]);
}

·

T3 老司机的狂欢

这个题是真的恶心到我了,以下是我调这个题的过程:

刚开始做的时候,完全不能理解题意

半个小时之后,完全不知道该怎么做

然后考完了,我听他们讲,啥玩意树上倍增,我去你*的

刚开始改这个题,我只想拿部分分,然后想打树状数组优化的dp,发现我开不出来树状数组

15min later,我去问MAX,他说你就再离散化一边,我人傻了

10min later,我打出来了第一问,但是评测机不给分,我不服

10min later,我输出了个-1,部分分给我了

后来oj炸了,我就自己把spj改了改,加上我的bash,搞了个评测机,这个东西大大提高了我的改题效率

不久之后,我开始想正解,我直接想到,我能不能直接记录转移节点???

然后我就记录了,但是程序bug极多,改用离散化下标的没有用,改用id的也没用

1h later,我成功的调出来了,并且,我把样例过了。。。叫上去,仍然是60

1h later,我又仔细的调了调,拿到65分,但是后来一直高不上去了

然后此时已经过去了一上午。。。。。

下午来了,经过一中午的思考,我明白了,我不能保证每一个的最优转移节点就是最后的答案,因为完全有可能一个大的前面接个更小的

然后我开始打树上倍增,并没有把它运用到树状数组中,只利用它判断了最后一个人的前面,这样还是不能保证是最优解

然后下一场考试开始了

然后考完之后,我又想明白了,在树状数组的每一次转移都加上倍增判断,过掉了这个题

AC_code


#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define pa pair<int,int>
const int N=1e5+5;
int n,K;
struct CAR{
	ll x,a;
	int id;
}sca[N];
bool cmp(CAR x,CAR y){
	return x.x<y.x;
}
ll nox[N],lsh[N];
struct sz_tree{
	int tr[N];
	int lb(int x){return x&(-x);}
	void ins(int x,int v){
		for(re i=x;i<=n;i+=lb(i))
			tr[i]=max(tr[i],v);
	}
	int query(int x){
		int ret=0;
		for(re i=x;i;i-=lb(i))
			ret=max(ret,tr[i]);
		return ret;
	}
	void clear(){memset(tr,0,sizeof(tr));}
}sz;
int jt[N];
bool check(int tim){
	for(re i=1;i<=n;i++){
		nox[i]=sca[i].x*2+sca[i].a*tim*tim;
		lsh[i]=nox[i];
	}
	sort(lsh+1,lsh+n+1);
	for(re i=1;i<=n;i++){
		nox[i]=lower_bound(lsh+1,lsh+n+1,nox[i])-lsh;
		int tmp=sz.query(nox[i]-1)+1;
		sz.ins(nox[i],tmp);
	}
	jt[tim]=sz.query(n);sz.clear();
	if(jt[tim]>=K)return true;
	else return false;
}
int fa[N][25],st[N][25];
void build(int x,int f){
	fa[x][0]=st[x][0]=f;
	for(re i=1;i<=20;i++){
		fa[x][i]=fa[fa[x][i-1]][i-1];
		st[x][i]=min(st[x][i-1],st[fa[x][i-1]][i-1]);
	}
}
bool fcheck(pa x,pa y){
	if(x.first!=y.first)return x.first<y.first;
	int mx,my,ax,ay;
	mx=ax=x.second;
	my=ay=y.second;
	for(re i=20;i>=0;i--){
		if(fa[ax][i]!=fa[ay][i]){
			mx=min(mx,st[ax][i]);
			my=min(my,st[ay][i]);
			ax=fa[ax][i];
			ay=fa[ay][i];
		}
	}
	return mx>my;
}
struct fsz_tree{
	pa tr[N];
	int lb(int x){return x&(-x);}
	void ins(int x,pa v){
		for(re i=x;i<=n;i+=lb(i))
			if(fcheck(tr[i],v))
				tr[i]=v;
	}
	pa query(int x){
		pa ret=make_pair(0,0);
		for(re i=x;i;i-=lb(i))
			if(fcheck(ret,tr[i]))
				ret=tr[i];
		return ret;
	}
}fsz;
int ji[N];
signed main(){
	scanf("%d%d",&n,&K);
	for(re i=1;i<=n;i++)scanf("%lld%lld",&sca[i].x,&sca[i].a),sca[i].id=i;
	sort(sca+1,sca+n+1,cmp);
	int l=0,r=86400;
	while(l<r){
		int mid=l+r+1>>1;
		if(check(mid))l=mid;
		else r=mid-1;
	}
	printf("%d\n",l);
	if(jt[l]>K)printf("-1");
	else{
		for(re i=1;i<=n;i++)lsh[i]=nox[i]=sca[i].x*2+1ll*sca[i].a*l*l;
		sort(lsh+1,lsh+n+1);
		for(re i=1;i<=n;i++){
			nox[i]=lower_bound(lsh+1,lsh+n+1,nox[i])-lsh;
			pa tmp=fsz.query(nox[i]-1);
			build(sca[i].id,tmp.second);
			fsz.ins(nox[i],make_pair(tmp.first+1,sca[i].id));
		}
		int ans=fsz.query(n).second;
		for(re i=1;i<=K;i++)ji[i]=ans,ans=fa[ans][0];
		sort(ji+1,ji+K+1);
		for(re i=1;i<=K;i++)printf("%d\n",ji[i]);
	}
}

啊啊啊啊,真爽!!!!

posted @ 2021-07-19 11:46  fengwu2005  阅读(53)  评论(0编辑  收藏  举报