2019.08.17【NOIP提高组】模拟 A 组

前言

毒瘤出题人


JZOJ 6290 倾斜的线

题目

在这里插入图片描述


分析

考虑按照这些点与斜率 p / q p/q p/q的截距从小到大排序,那么可以证明相邻两个点更接近斜率,然后暴力求解,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#define rr register
using namespace std;
struct rec{int x,y; double b;}a[200001];
int n,p,q,h1,h2,mark; double ans,h;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
bool cmp(rec a,rec b){return a.b<b.b;}
signed main(){
	freopen("slope.in","r",stdin);
	freopen("slope.out","w",stdout);
	n=iut(); p=iut(); q=iut(); h=p*1.0/q; ans=1e18;
	for (rr int i=1;i<=n;++i) a[i]=(rec){iut(),iut(),0};
	for (rr int i=1;i<=n;++i) a[i].b=a[i].y-h*a[i].x;
	sort(a+1,a+1+n,cmp);
	for (rr int i=1;i<n;++i){
		double t=(a[i+1].y-a[i].y)*1.0/(a[i+1].x-a[i].x);
		if (abs(t-h)<ans) ans=abs(t-h),mark=i;
	}
	rr int h1=a[mark+1].y-a[mark].y,h2=a[mark+1].x-a[mark].x,t=__gcd(h1,h2);
	return !printf("%d/%d\n",h1/t,h2/t);
} 

JZOJ 6305 最小值

题目

在这里插入图片描述


分析

首先朴素的dp方程是 d p [ i ] = m i n { d p [ j ] + F ( m i n { a j + 1 ∼ a i } ) } dp[i]=min\{dp[j]+F(min\{a_{j+1}\sim a_i\})\} dp[i]=min{dp[j]+F(min{aj+1ai})}
考虑用一个单调递增的栈记录 a i a_i ai那么栈里的可以表示成选择分割的分界点,那么可以 O ( n ) O(n) O(n)解决问题


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long ll;
const int N=200001; int n,a[N],rk[N],top;
ll f[N],w[N],sum[N],dp[N],aa,bb,cc,dd;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline ll max(ll a,ll b){return a>b?a:b;}
signed main(){
	freopen("min.in","r",stdin);
	freopen("min.out","w",stdout);
	n=iut(),aa=iut(),bb=iut(),cc=iut(),dd=iut(); sum[0]=-1ll<<60;
	for (rr int i=1;i<=n;++i) a[i]=iut();
	for (rr int i=1;i<=n;++i) f[i]=aa*a[i]*a[i]*a[i]+bb*a[i]*a[i]+cc*a[i]+dd;
	for (rr int i=1;i<=n;++i){
		rr ll mx;
		for (mx=dp[i-1];top&&a[rk[top]]>a[i];--top) mx=max(mx,w[top]);
		rk[++top]=i,w[top]=mx,sum[top]=max(sum[top-1],mx+f[i]);
		dp[i]=sum[top];
	}
	return !printf("%lld\n",dp[n]);
}

JZOJ 6307 安排

题目

给定一个长度为 n ≤ 4096 n≤4096 n4096的排列,每次可以交换一个区间的最大值和最小值,求 345678 345678 345678次询问内将一个排列变为另一个排列。


分析

由于操作可逆,问题可以转化为将两个序列分别排序,那么想把一段区间的最小值移到最前端,用快速排序解决,时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)


代码

#include <cstdio>
#include <cctype>
#define rr register
#define swap(x,y) (x^=y,y^=x,x^=y)
using namespace std;
int a[4101],lef[345701],rig[345701],ans,ans1,n;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void doit(int l,int r){
	for (rr int head=l,tail=r;head<tail;++head,--tail)
		swap(a[head],a[tail]),lef[++ans]=head,rig[ans]=tail;	
}
inline void mergesort(int l,int mid,int r){
	if (l>mid||r<=mid||l==r) return;
	rr int i=mid,j=mid+1;
	while (l<i&&j<r&&a[i-1]>a[j+1]) --i,++j;
	if (a[i]>a[j]){
	    doit(i,mid),doit(mid+1,j),doit(i,j);				    
		mergesort(l,i-1,mid),mergesort(mid+1,j,r);
	}
}
inline void merge(int l,int r){
	if (l==r) return;
	rr int mid=(l+r)>>1;
	merge(l,mid);
	merge(mid+1,r);
	mergesort(l,mid,r);
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void prnt(int i){putchar(10),print(lef[i]),putchar(32),print(rig[i]);}
signed main(){
	freopen("swap.in","r",stdin);
	freopen("swap.out","w",stdout);
	n=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut(); merge(1,n),ans1=ans;
	for (rr int i=1;i<=n;++i) a[i]=iut(); merge(1,n),print(ans);
	for (rr int i=1;i<=ans1;++i) prnt(i);
	for (rr int i=ans;i>ans1;--i) prnt(i);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值