2019.11.05【NOIP提高组】模拟 B 组

本文提供了解决地图密度计算、酿酒厂选址、矩形连通块计数和平坦折线覆盖问题的代码实现。通过高效算法解决实际问题,包括O(n^2)复杂度的酿酒厂选址问题和矩形连通块计数的分类讨论方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JZOJ 3831 地图的密度(水题)

代码

#include <cstdio>
#include <cctype>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,a[261][261];
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 print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
signed main(){
	freopen("map.in","r",stdin);
	freopen("map.out","w",stdout);
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j)
		a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+iut(); 
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j){
		rr int lx=max(i-m,1),ly=max(j-m,1),rx=min(i+m,n),ry=min(j+m,n);
		print(a[rx][ry]-a[lx-1][ry]-a[rx][ly-1]+a[lx-1][ly-1]),putchar(j==n?10:32); 
	}
	return 0;
}

JZOJ 3832 在哪里建酿酒厂(水题)

代码(O(n^2)卡常AC)

#include <cstdio>
#include <cctype>
#define rr register
#define min(a,b) ((a)>(b)?(b):(a))
using namespace std;
const int N=20011; typedef long long ll;
int n,a[N],dis[N]; ll pre[N],suf[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;
}
signed main(){
	freopen("bro.in","r",stdin);
	freopen("bro.out","w",stdout);
	n=iut(); rr ll ans=1e16;
	for (rr int i=1;i<=n;++i) a[i]=a[i+n]=iut(),dis[i]=dis[i+n]=iut();
	for (rr int i=2;i<=n*2;++i) a[i]+=a[i-1];
	for (rr int i=1;i<=n;++i){
		rr int l=i,r=i+n-1; pre[l]=suf[r]=0; rr ll now=1e16;
		for (rr int j=l+1;j<=r;++j) pre[j]=pre[j-1]+1ll*(a[j-1]-a[l-1])*dis[j-1];
		for (rr int j=r-1;j>=l;--j) suf[j]=suf[j+1]+1ll*(a[r]-a[j])*dis[j];
		for (rr int j=l;j<=r;++j) now=min(now,pre[j]+suf[j]); ans=min(ans,now);
	}
	return !printf("%lld",ans);
}
想看正解看看这个(https://blog.csdn.net/Mr_wuyongcong/article/details/102915841)

JZOJ 1956 洛谷 2449 矩形

题目

问多个矩形组成的图形中有多少个连通块


分析

分类讨论,即可(我原来洛谷AC代码结果WA掉了QAQ)


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
struct rec{int lx,ly,rx,ry;}a[7011];
int n,f[7011],ans,cnt[7011];
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 signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
signed main(){
	freopen("pro.in","r",stdin);
	freopen("pro.out","w",stdout);
	n=iut();
	for (rr int i=1;i<=n;++i) f[i]=i;
	for (rr int i=1;i<=n;++i){
		a[i]=(rec){iut(),iut(),iut(),iut()};
        for (rr int j=1;j<i;++j){
        	rr rec x=a[i],y=a[j],t; rr bool flag=0;
        	if (x.lx>y.lx||(x.lx==y.lx&&x.ly>y.ly)) t=x,x=y,y=t;
        	if (x.ly<=y.ly&&(y.lx<=x.rx&&y.ly<=x.ry)&&(x.rx!=y.lx||x.ry!=y.ly)) flag=1;
        	if (x.ly>y.ly&&(y.lx<=x.rx&&y.ry>=x.ly)&&(x.rx!=y.lx||x.ly!=y.ry)) flag=1;
        	if (flag){
        		rr int fa=getf(i),fb=getf(j);
        		rr int fc=fa<fb?fa:fb;
        		if (fa!=fb) f[fc]=fa^fb^fc;
			}
		}
	}
	for (rr int i=1;i<=n;++i) ans+=f[i]==i;
	return !printf("%d",ans);	
}

JZOJ 3833 平坦的折线

题目

现在我们在一张纸上有一个笛卡尔坐标系。我们考虑在这张纸上用铅笔从左到右画的折线。我们要求任何两个点之间连接的直线段与 x x x轴的夹角在 − 45 ∼ 45 -45\sim 45 4545之间,一条满足以上条件的折线称之为平坦的折线。假定给出了 n n n个不同的整点(坐标为整数的点),最少用几条平坦的折线可以覆盖所有的点?


分析

考虑把它转换,首先把坐标系逆时针旋转45度,也就是
x ′ = x ∗ cos ⁡ θ + y ∗ sin ⁡ θ , y ′ = y ∗ cos ⁡ θ − x ∗ sin ⁡ θ x'=x*\cos\theta+y*\sin\theta,y'=y*\cos\theta-x*\sin\theta x=xcosθ+ysinθ,y=ycosθxsinθ
然后按照第一关键字为横坐标从小到大排列,第二关键字为纵坐标从大到小排列,按照纵坐标求最长不下降子序列长度即可


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=30011;
struct rec{int x,y;}a[N]; int n,b[N],len;
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.x<b.x||(a.x==b.x&&a.y>b.y);} 
signed main(){
	freopen("lam.in","r",stdin);
	freopen("lam.out","w",stdout);
	n=iut();
	for (rr int i=1;i<=n;++i){
		rr int x=iut(),y=iut();
		a[i]=(rec){x+y,y-x};
	}
	sort(a+1,a+1+n,cmp);
	b[++len]=a[1].y;
	for (rr int i=2;i<=n;++i){
		if (a[i].y>b[len]) b[++len]=a[i].y;
		else b[lower_bound(b+1,b+1+len,a[i].y)-b]=a[i].y;
	}
	return !printf("%d",len);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值