纪中集训 Day27&Day28

纪中集训 Day27&Day28

T1
真心没懂,打了个暴力

T2
二分少了个=

T3&T4
我太菜了
其实就是分组背包和BFS而已


T1

水果盛宴(fruit)

题目
贝茜又再一次地闯入了 F a r m e r Farmer Farmer J o h n John John 的房子!她在厨房发现了一堆柠檬和一堆橘子(每堆都有无限多个),并且,她希望尽可能地多吃。
贝茜的有一个饱腹值上限 T(1<=T<=5,000,000)。吃一个橘子会增加她 A A A 点饱腹值,吃一个柠檬会增加她 B B B 点饱腹值(1<= A A A, B B B<= T T T),如果她愿意,贝茜可以最多喝一次水,这会立即使她的饱腹值变成一半,请你帮助贝茜求出她可以获得的最大饱腹值。

输入
一行三个整数 T T T, A A A B B B

输出
一行一个整数,表示贝茜可获得的最大饱腹值

样例
input
8 5 6

output
8

解题思路
先做一次完全背包
然后将它们所在格的坐标和所在格坐标除以2或运算一下
再做一遍完全背包

代码

#include<iostream>
#include<cstdio>
using namespace std;
int t,a,b,x,y,z,len=2,c=2,l,r,mid;
int f[5000010],m[2600000];
int main()
{
	freopen("fruit.in","r",stdin);
	freopen("fruit.out","w",stdout);
	scanf("%d%d%d",&t,&a,&b);
	f[a]=1;
	f[b]=1;
	for (int i=1;i<=t;i++)  //完全背包
	{
	    if (i-a>0)
		   f[i]=max(f[i-a],f[i]);
		if (i-b>0)
		   f[i]=max(f[i-b],f[i]);
	}
	for (int i=1;i<=t;i++)  //喝水,除2进行或运算
	    f[i/2]|=f[i];
	for (int i=1;i<=t;i++)  //再来一次完全背包
	{
		if (i-a>0)
		   f[i]=max(f[i],f[i-a]);
		if (i-b>0)
		   f[i]=max(f[i],f[i-b]);
		if (f[i]==1)
		   x=i;
	}
	cout<<x<<endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T2

愤怒的奶牛2(angry)

题目
贝茜这头奶牛设计了她所认为的下一个热门视频游戏—“愤怒的奶牛”。她认为这是她完全原创的:玩家将一个弹弓射到一个一维的场景中,该场景由位于数字线上各个点的一组干草包组成。每只奶牛都有足够的力量引爆其落地地点附近的干草包,我们的目的是使用一系列奶牛引爆所有的干草包。
N N N捆干草包位于这一行的不同整数位置 x x x 1,x2,…,xN,如果一头奶牛以能量 R R R着陆在了数轴上的任意一个位置x,那么会引起半径为 R R R R R R- x x x R R R+x)的爆炸,并摧毁范围内的所有干草包。
一共有 K K K头奶牛允许被用来作为炮弹,每头奶牛的能量R都相同。请帮忙决定这个最小的能量,使得用这 K K K头奶牛可以摧毁所有的干草包。

输入
第一行包含两个整数 N N N, K K K(1<= N N N<=50,000,1<= K K K<=10)
接下来 N N N行,每行包含一个整数 x i xi xi,表示每捆干草包的位置(0<= x i xi xi<=1,000,000,000)

输出
一行一个整数,表示最少所需要的每头奶牛的能量值 R R R

样例
input
7 2
20
25
18
8
10
3
1

output
5

解题思路
二分能量就好

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,l,r,mid,x,k;
int a[50010];
int check()
{
	 x=a[1];
	 k=0;
	 for (int i=2;i<=n;i++)  //分段,看需要多少头牛
		 if (a[i]-x>mid*2)
		 {
		    k++;
		    x=a[i];
		}
	 k++; 
	 return k;  //返会需要的牛的头数
}
int main()
{
//	freopen("angry.in","r",stdin);
//	freopen("angry.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	l=1,r=(a[n]-a[1])*2;
	while (l<=r)
	{
		  mid=(l+r+1)/2;  
	      if (check()<=m)  //少了给右,多了给左
		     r=mid-1;
			 else l=mid+1;  
	}
	cout<<l<<endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T3

采访(interview)

题目
你是一名记者,现在要求你去采访 n n n 个国家的领导人。采访每一个国家的领导人需要消耗你的时间为 t t t[ i i i],但你可以收获价值为 v v v[ i i i]的信息,然后就能写成报道……
然而尴尬的是,有一些国家之间的关系属于敌对关系,因此如果一个国家的领导人知道你采访了他的敌对国家领导人,那么他就会拒绝你的采访。总之,你采访的国家中,任意选出一对国家都不能构成敌对关系,你才能够完成你的采访,否则某些部分就要落空。
你的 B o s s Boss Boss他给了你一个时间限制 T T T,如果你在时间限制内没有完成采访任务,你就会被炒鱿鱼。当然,他希望你在时间限制 T T T 内完成的采访累计起来的价值总和最大。

输入
第一行有三个数,第一个数为时间限制T,第二个数为国家数量n,第三个数为国家之间的敌对组数m。
接下来 n n n 行,每行两个数,第一个数为 t t t[ i i i],第二个数为 v v v[ i i i]。
接下来 m m m 行,每行有 m m m[ i i i]+1 个数,首先输入m[i],表示这一组中一共有多少国家是敌对关系,之后输入m[i]个数,表示这m[i]个国家两两之间为敌对关系(一组敌对关系的国家中,每两个国家都构成敌对关系,比如这一组是1,3,4,那么1 和3,1 和4,3 和4 都构成敌对关系),若 m m m[ i i i] = 1,那么这个国家与其他国家都不构成敌对关系。

输出
一个整数,表示最大价值 V V V

样例
input
10 5 2
5 10
7 9
6 3
1 13
8 1
3 1 3 4
2 2 5

output
22

数据范围限制
60%的数据: m m m=1;
100%的数据:0≤ T T T≤50000,0≤ n n n≤500,1≤ m m m≤10, n n n=∑ m m m[ i 4 ] , 即 i4],即 i4]m [ 1 ] + [1]+ [1]+m [ 2 ] + . . . . . = [2]+.....= [2]+.....=n$,且敌对关系中每个国家编号只会出现一次。

解题思路
分组背包模板套一套
二维的哈

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,d,m,t[520],q[520],a[12][120],f[520][50010];
int main()
{
	freopen("interview.in","r",stdin);
	freopen("interview.out","w",stdout);
	scanf("%d%d%d",&d,&n,&m);
	for (int i=1;i<=n;i++)
	    scanf("%d%d",&t[i],&q[i]);
	for (int i=1;i<=m;i++)
	{
		scanf("%d",&a[i][1]);
		for (int j=1;j<=a[i][1];j++)
		    scanf("%d",&a[i][j+1]);
	}
	for (int i=1;i<=m;i++)
	{
		for (int j=1;j<=d;j++)
		    f[i][j]=f[i-1][j];
		for (int j=2;j<=a[i][1]+1;j++)
		    for (int k=d;k>=t[a[i][j]];k--)
		        f[i][k]=max(f[i][k],f[i-1][k-t[a[i][j]]]+q[a[i][j]]);
	}
	cout<<f[m][d]<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T4

房间开灯(light)

题目
F a r m e r Farmer Farmer J o h n John John 最近正在修建一个巨大的包含 N N N× N N N 个房间的牲口棚,这些房间从(1,1)标号到( N N N, N N N)。由于某些原因而害怕黑暗,贝茜这头奶牛想要尽可能地开更多房间的灯。贝茜从房间(1,1)出发,这个房间是唯一一个一开始就亮着的房间。在一些房间中,她会找到一些电灯开关,这些开关她可以用来切换其他房间的灯的状态。比如,在(1,1)这个房间中可能存在一个电灯开关来控制(1,2)房间中的电灯。贝茜只能进电灯开着的房间,并且贝茜只能从房间( x x x, y y y)走到四个方向的房间( x x x-1, y y y),( x x x+1, y y y),( x x x, y y y-1)和( x x x, y y y+1)(如果在边界的话,那可能会更少)。请帮忙统计贝茜最多可以照亮多少房间。

输入
第一行两个整数 N N N M M M(2<= N N N<=100,1<= M 4 < = 20 , 000 ) 下 面 4 M M4<=20,000) 下面 4M M4<=20,0004M 行,每行用四个整数 x x x, y y y, a a a, b b b 来表示房间( x x x, y y y)存在着可以控制房间( a a a, b b b)的灯的开关。一个房间可能有多个开关,一个房间的灯的开关可能存在于多个房间中。

输出
一行一个整数,表示贝茜最多可以照亮的房间数

样例
3 6
1 1 1 2
2 1 2 2
1 1 1 3
2 3 3 1
1 3 1 2
1 3 2 1

output
5

提示
在这个样例中,贝茜可以使用房间(1,1)内的开关打开房间(1,2)和(1,3)的灯。然后她可以走到(1,3),使用(1,3)内的开关打开(2,1)的灯,接着可以通过(2,1)打开(2,2)的灯,然而(2,3)是黑暗的,她无法去打开(2,3)房间里的开关,因此,她最多只能打开 5个房间里的灯。

解题思路
将BFS改一下
前面用邻接表将此房间内存的开灯按钮所有都打开

代码

#include<iostream>
#include<cstdio>
using namespace std;
struct hhx{
	int x,y,next;
}a[20010];
int f[20010][2],p[120][120],m[120][120],head[120][120];
int fx[5]={0,0,0,1,-1},fy[5]={0,1,-1,0,0};
int n,k,x,y,x1,y1,t,h,ma;
int main()
{
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	scanf("%d%d",&n,&k);
	for (int i=1;i<=k;i++)
	{
		scanf("%d%d%d%d",&x,&y,&x1,&y1);
		a[i].x=x1;
		a[i].y=y1;
		a[i].next=head[x][y];
		head[x][y]=i;
	}
	t=1;
	p[1][1]=1;
	f[1][1]=1;
	f[1][2]=1;
	m[1][1]=1;
	do{
		h++;
		int i=head[f[h][1]][f[h][2]];
		while (i>0)  //开灯
		{
			  m[a[i].x][a[i].y]=1;  
			  i=a[i].next;
		}
		for (int j=1;j<=h;j++)  //普通的bfs
		{
		    for (int i=1;i<=4;i++)
		    {
			    int xx=f[j][1]+fx[i],yy=f[j][2]+fy[i]; 
			    if (xx>0&&x<=n&&y>0&&y<=n&&p[xx][yy]==0&&m[xx][yy]==1)
			    {
				   p[xx][yy]=1;
				   f[++t][1]=xx;
				   f[t][2]=yy;
		    	}
		    }
		}
	}while (h<t);
    for (int i=1;i<=n;i++)  //找开了的灯
        for (int j=1;j<=n;j++)
            if (m[i][j]==1)
			   ma++; 
	cout<<ma<<endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值