2019jzoj10.7

2019.10.07【NOIP普及组】模拟赛C组

	T1      trapped

	T2      小x的密室
		
	T3      修剪草坪
			
	T4	修建泳池

T1

题目描述
FJ 刚刚收到了一批N(1 N 4000) 堆的甘草。他把它们放在一条通向谷仓的路上的多个地方。不幸的是,他完全忘记了Bessie 在沿着这条路上啃食牧草,她有可能现在被困在了这些甘草堆里了!

每堆牧草j 有一个大小Sj 以及一个独特的在一维道路上的位置Pj。Bessie 从某一个没有甘草的位置开始,并可以在路上自由行走,甚至可以到达有甘草堆的位置,不过她不能越过这个位置。有一个例外;如果她以同样的方向跑D 个单位的长度,她可以积累足够的速度,冲破并且永久清除任何大小严格小于D 的干草堆。当然,当做了这个动作之后,她就有更大的移动空间,可以使她对其它甘草堆发起一次奔跑,并永久地清除他们。

Bessie 冲向自由的条件是她最终可以冲破最左端或最右端的甘草堆。请计算一个总空间,从这些空间里的点出发将使Bessie 无法最终冲向自由。例如,如果Bessie 从1 与5 号干草堆之间的位置出发,她将不能冲破干草堆;那么这一段的空间就是4.

				输入
				第一行输入包含N。接下来的N 行每行描述一个干草堆,两个整数,一个大小,一个位置,范围都是1..10^9
			
		
			
				输出
				打印一个整数,Bessie 不能逃脱的空间的总面积

样例输入
5
8 1
1 4
8 8
7 15
4 20

样例输出
14

			数据范围限制
			• 对于100% 的数据,N <= 4000。

这题暴力

#include<iostream>
#include<cstdio>
using namespace std;
int m,n,k,x,y,a[1000010],b[100010],ans;
void qsort(int l,int r){
 if(l>r)return;
 int i=l,j=r,m=b[j],sw;
 while(i<=j){
  while(b[i]<m)i++;
  while(b[j]>m)j--;
  if(i<=j){
   sw=a[i];
   a[i]=a[j];
   a[j]=sw;
   sw=b[i];
   b[i]=b[j];
   b[j]=sw;i++;j--;
  } 
 }
 qsort(l,j);
 qsort(i,r);
}
int main(){
 freopen("trapped.in","r",stdin);
 freopen("trapped.out","w",stdout);
 cin>>m;
 for(int i=1;i<=m;i++)
 cin>>a[i]>>b[i];
 qsort(1,m);
 for(int i=1;i<m;i++){
  int l=i,r=i+1;
  bool f=1;
  int sum=b[r]-b[l];
  while(l>=1&&r<=m){
   f=0;
   int mid=b[r]-b[l];
   if(mid>a[l])l--,f=1;
   if(mid>a[r])r++,f=1;
   if(!f)break;
  }
  if(l>=1&&r<=m)ans+=sum;
 }
 cout<<ans;
 return 0;
}

T2

用状压BFS

#include<iostream>
#include<cstring>
using namespace std;
int m,n,k,x,y,key[5001],roomkey[5011][5011][2];
int b[1000010][4],f[5001][1500];
bool check(int x,int y){
	string s="",ss="";
	while(x!=0){
		s+=(x%2)+'0';
		x/=2;
	}
	while(y!=0){
		ss+=(y%2)+'0';
		y/=2;
    }
    int i=0;
	while(i<ss.size()){
		if(s[i]=='0'&&ss[i]=='1')return 0;
		i++;
	}
	return 1;
}
int bx(int x,int y){
	string s="",ss="",st="";
	while(x!=0){
		s+=(x%2)+'0';
		x/=2;
	}
	while(y!=0){
		ss+=(y%2)+'0';
		y/=2;
    }
	int sum=0;
	k=max(s.size(),ss.size());
	int i=0;
	while(i<k){
		if(s[i]=='1'||ss[i]=='1')st='1'+st;
		else st='0'+st;
		i++;
	}
	for(int i=0;i<st.size();i++)
	sum=(st[i]-'0')*(1<<s.size()-1-i);
	return sum;
}
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=k;j++)
	  {
	  	cin>>x;
	  	key[i]+=x*(1<<k-j);
	  }
	for(int i=1;i<=m;i++)
	{
		int z;
		cin>>x>>y;
		roomkey[x][0][1]++;
		roomkey[x][roomkey[x][0][1]][1]=y;
		for(int j=1;j<=k;j++){
			cin>>z;
			roomkey[x][roomkey[x][0][1]][0]+=z*(1<<k-j);
	    }
	}
	int head=0,tail=1;
	f[1][key[1]]=1;b[1][1]=1;b[1][2]=key[1];
	while(head<tail){
		head++;
		x=b[head][1];
		for(int i=1;i<=roomkey[x][0][1];i++){
			if(check(b[head][2],roomkey[x][i][0])){
				tail++;
				b[tail][1]=roomkey[x][i][1];
				b[tail][2]=bx(b[head][2],key[i]);
				b[tail][3]=b[head][3]+1;
				if(roomkey[x][i][1]==n){
					cout<<b[tail][3];
					return 0;
				}
				if(f[roomkey[x][i][1]][b[tail][2]])tail--;
				f[roomkey[x][i][1]][b[tail][2]]=1;
			}
		}
	}
	cout<<"No Solution";
	return 0;
}

T3

题目描述
在一年前赢得了小镇的最佳草坪比赛后,约翰变得懒惰了,再也没有修剪过草坪。现在,新一轮的比赛又开始了,约翰希望能够再次夺冠。然而,约翰家的草坪非常脏乱,因此,约翰需要让他的奶牛来完成这项工作。约翰家有N头奶牛,排成一直线,编号为1到N。每只奶牛的能力是不同的,第i头奶牛的能力为Ei。靠在一起的奶牛很熟悉,所以如果安排相邻的K+1头奶牛一起工作,她们就会密谋罢工,所以不能选中连续的K+1头奶牛。因此,约翰需要你的帮助。如何挑选奶牛,才能使她们的能力之和最高呢?

				输入
				第一行:两个用空格隔开的整数:N和K,1≤ N≤ 100000,1≤ K≤ N

第二行到N+1行:第i+1行有一个整数,表示第i头牛的能力Ei,1≤ Ei <= 10^9

				输出
				第一行:单个整数,表示最大的能力之和

样例输入
5 2
1
2
3
4
5

样例输出
12

			数据范围限制
			对于30% 的数据,有1 ≤ n ≤ 10。

对于60% 的数据,有1 ≤ n ≤ 2, 000。

对于100% 的数据,有1 ≤ n≤ 100, 000。

				提示
				(除了第三头以外的所有奶牛都选,总能力为1+2+4+5=12)

用DP+单调队列优化

#include<bits/stdc++.h>
using namespace std;
long long k,m,n,a[100010],q[100010],f[100010];
int main(){
	k=0;
	scanf("%lld%lld",&m,&n);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld",&a[i]);
		k+=a[i];
	}
	long long head=1,tail=1;
    for(long long i=1;i<=m;i++){
       while(head<=tail&&i-q[head]>n+1)head++;
       f[i]=a[i]+f[q[head]];
       while(head<=tail&&f[q[tail]]>=f[i])tail--;
       q[++tail]=i;
	}
	long long minn=f[m];
	for(long long i=m-n;i<m;i++)minn=min(minn,f[i]);
	printf("%lld",k-minn);
	return 0;
}

T4

题目描述
夏天到了,学校打算在教学楼后面的空地上挖一个泳池供大家使用。

经过实地勘察,这块土地可以划分成N 行M 列的方格,有的方格是树,有的方格是空地。现在要找一块最大的矩形空地修建泳池,请问泳池的面积有多大?

				输入
				第一行两个正整数N, M,分别表示土地的行数和列数。

接下来N行,每行有M个用空格隔开的数a[i][j],每个数均为0或1,0表示空地,1表示树。

				输出
				输出一行一个整数,表示最大的泳池面积。

样例输入
【样例输入1】
4 5
0 1 0 1 0
0 0 0 0 0
0 0 0 0 1
1 0 0 0 0

【样例输入2】
4 5
1 1 0 1 1
1 1 0 0 1
1 0 0 0 0
0 0 0 0 0

样例输出
【样例输出1】
9

【样例输出2】
8

			数据范围限制
			对于10%的数据,所有的0构成一个纯天然的长方形区域

对于30%的数据,所有的0构成若干个互不相交的有树隔开的长方形区域

对于另外30%的数据,所有的0构成一个柱状图,即每一列所有的1都在该列的最上方

对于100%的数据,1<=N, M<=2000

这题枚举最左最右,再有上的最小值(直到有1)相乘,再找MAX

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int m,n,k,f1[2001][2001],a[2001][2001],f2[2001][2001],f3[2001][2001];
int main(){
	freopen("pool.in","r",stdin);
	freopen("pool.out","w",stdout);
	cin>>m>>n;
	memset(a,1,sizeof(a));
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
			if(a[i][j]==0){
				if(a[i][j-1]==0)f1[i][j]=f1[i][j-1]+1;
		        else f1[i][j]=1;
		    }
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=n;j>=1;j--){
			if(a[i][j]==0){
				if(a[i][j+1]==0)f2[i][j]=f2[i][j+1]+1;
			    else f2[i][j]=1;
			}
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]==0){
				if(a[i-1][j]==0){
					f3[i][j]=f3[i-1][j]+1;
					f1[i][j]=min(f1[i][j],f1[i-1][j]);
					f2[i][j]=min(f2[i][j],f2[i-1][j]);
				}
				else f3[i][j]=1;
			}
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			int sum=(f2[i][j]+f1[i][j]-1)*f3[i][j];
			if(sum>k)k=sum;
		}
	}
	cout<<k;
	return 0;
}

可能做得不好,但是是给自己看的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值