2019.11.08【NOIP提高组】模拟 B 组

解题报告

  • 洛谷 2872 道路建设
    • 代码(Kruskal)
  • 洛谷 2873 泥水坑
    • 代码(广搜)
  • 洛谷 2869 美食的食草动物
    • 题目
    • 分析
    • 代码
  • 洛谷 2870 最佳牛线
    • 题目
    • 分析
    • 代码

洛谷 2872 道路建设

代码(Kruskal)

#include 
#include 
#include 
#include 
#define rr register
using namespace std;
const int N=1001;
struct rec{int x,y; long long w;}a[N*N];
int n,m,xx[N],yy[N],f[N],now,tot; double ans;
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;
}
bool cmp(const rec a,const rec b){return a.w<b.w;}
inline long long w(int x){return 1ll*x*x;}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
signed main(){
	n=iut(),m=iut();
	for (rr int i=1;i<=n;++i)
		xx[i]=iut(),yy[i]=iut(),f[i]=i;
	for (rr int i=1;i<=m;++i){
		rr int x=getf(iut()),y=getf(iut());
		if (x>y) x^=y,y^=x,x^=y;
		if (x!=y) ++now,f[x]=y;
	}
	for (rr int i=1;i<n;++i)
	for (rr int j=i+1;j<=n;++j)
		if (getf(i)!=getf(j)) a[++tot]=(rec){i,j,w(xx[i]-xx[j])+w(yy[i]-yy[j])};
	sort(a+1,a+1+tot,cmp);
	for (rr int p=1;now<n-1;++p){
		rr int fa=getf(a[p].x),fb=getf(a[p].y);
		if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
		if (fa!=fb)	++now,ans+=sqrt(a[p].w),f[fa]=fb;
	}
	return !printf("%.2lf",ans);
} 

洛谷 2873 泥水坑

代码(广搜)

#include 
#include 
#include 
#define rr register
using namespace std;
const int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
struct rec{int x,y;}; int zx,zy,n,dis[1011][1011];
bool v[1011][1011];
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;
}
signed main(){
	zx=iut()+500,zy=iut()+500,n=iut();
	for (rr int i=1;i<=n;++i){
		rr int xx=iut()+500,yy=iut()+500;
		v[xx][yy]=1;
	}
	rr queue<rec>q; q.push((rec){zx,zy});
	v[zx][zy]=1; dis[zx][zy]=0;
	while (q.size()){
		rr int nx=q.front().x,ny=q.front().y; q.pop();
		if (nx==500&&ny==500) return !printf("%d",dis[nx][ny]);
		for (rr int k=0;k<4;++k){
			rr int qx=nx+dx[k],qy=ny+dy[k];
			if (qx<0||qy<0||qx>1000||qy>1000||v[qx][qy]) continue;
			v[qx][qy]=1,dis[qx][qy]=dis[nx][ny]+1; q.push((rec){qx,qy}); 
		}
	}
}

洛谷 2869 美食的食草动物

题目

其实题目应该翻译成美食家标准的食草动物
n n n头牛, m m m种饲料,牛所想要的是不低于它想要的价格以及不低于它想要的鲜美程度,每种饲料最多只能被一头牛享用,问农夫所需的最小费用


分析

首先,考虑按照鲜美程度从大到小排序,然后双指针,然后要取出费用最优的删掉,考虑用平衡树,但是STL::multiset不是更好吗


代码

#include 
#include 
#include 
#include 
#define rr register
using namespace std;
const int N=100011;
struct rec{
	int cost,fresh;
	bool operator <(const rec &t)const{
	    return fresh>t.fresh;
	}
}a[N],b[N];
multiset<int>uk; bool flag;
int n,m; long long ans;
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;
}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i)
		a[i]=(rec){iut(),iut()};
	for (rr int i=1;i<=m;++i)
	    b[i]=(rec){iut(),iut()};
	sort(a+1,a+1+n),sort(b+1,b+1+m);
	for (rr int i=1,j=1;i<=n;++i){
		while (j<=m&&b[j].fresh>=a[i].fresh) uk.insert(b[j++].cost);
		rr multiset<int>::iterator it=uk.lower_bound(a[i].cost);
		if (it==uk.end()) {flag=1; break;} ans+=*it; uk.erase(it);
	}
	printf("%lld",flag?-1:ans);
	return 0;
}

洛谷 2870 最佳牛线

题目

有一个字符串,可以从首尾取出一个字母,问依次组成的字符串字典序最小的方案


分析

首先如果一个字符串首尾字符不同,那么肯定选择小的,但问题是如果相等选其中一个会不会导致答案不优,所以考虑找到第一个不相等的位置,使用二分判定,用哈希求是否相等,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
后缀数组dalao太强了


代码

#include 
#include 
#define rr register
using namespace std;
typedef unsigned long long ull; const ull p=13731;
ull ba[500011],pr[500011],su[500011]; char a[500011]; int n,now;
inline ull spr(int l,int r){return pr[r]-ba[r-l+1]*pr[l-1];}
inline ull ssu(int l,int r){return su[l]-ba[r-l+1]*su[r+1];}
signed main(){
	scanf("%d",&n),ba[0]=1;
	for (rr int i=1;i<=n;++i) ba[i]=p*ba[i-1];
	for (rr int i=1;i<=n;++i){
		rr char c=getchar();
		while (!isalpha(c)) c=getchar();
		a[i]=c;
	}
	for (rr int i=1;i<=n;++i) pr[i]=p*pr[i-1]+(a[i]^64);
	for (rr int i=n;i>=1;--i) su[i]=p*su[i+1]+(a[i]^64);
	rr int l=1,r=n;
	while (l<=r){
		rr int L=1,R=(r-l+1)>>1;
		while (L<R){
			rr int mid=(L+R)>>1;
			if (spr(l,l+mid-1)==ssu(r-mid+1,r)) L=mid+1;
			    else R=mid;
		}
		if (a[l+L-1]<a[r-L+1]) putchar(a[l++]);
		    else putchar(a[r--]);
		if ((++now)%80==0) putchar(10);
	}
	return 0;
}

你可能感兴趣的:(模拟赛,平衡树,哈希&最小表示法)