20161102的考试】模拟,树的直径,推公式……三道水题然而浪飞了……

20 篇文章 0 订阅
8 篇文章 0 订阅

…………喵的……今天太浪了23333

三道题都会三道都GG【滚走

…………喵的…………在AK场没上百是怎样的体验*2


T1自信不对拍,然后发现好像自己naive了;

T2……喵的我fread开小了于是RE【智障脸

T3………………题意理解错*1,瞬间心态爆炸GGGGGGGG


T1:

题面:模拟一下连连看,找每个块有多少能和它消除的

思路:……模拟啊模拟,喵哒似乎是状态稍微记少了一点,反正是水题随便写写就能过的,比起dfs果然还是bfs比较好看

代码:

#include<bits/stdc++.h>
#define MAXN 36
#define INF 0x3f3f3f3f
#define push(a,b,c) que[tail++]=a,que[tail++]=b,que[tail++]=c
using namespace std;	int n,m;
const int cx[4] = {-1,0,1,0};
const int cy[4] = {0,1,0,-1};

int gph[MAXN][MAXN];
int cnt[MAXN][MAXN];

const int MAXQ = MAXN*MAXN*12;
int que[MAXQ],head,tail;

int dis[MAXN][MAXN][4];

inline void bfs(int x,int y){
	if(!gph[x][y])	return ;
	int x0=x,y0=y;
	memset(dis,INF,sizeof dis);
	head=tail=0;
	for(int dir=0;dir<4;++dir)
		dis[x][y][dir]=0,push(x,y,dir);

	int pre_dir;
	while(head^tail){
		x=que[head++],y=que[head++],pre_dir=que[head++];
		if(head==MAXQ)	head=0;
		
		if(dis[x][y][pre_dir]>=3)	continue;
		
		for(int dir=0;dir<4;++dir){
			int xx=x+cx[dir],yy=y+cy[dir];
			if(xx<0||xx>n+1||yy<0||yy>m+1)	continue;
			for(int dir2=0;dir2<4;++dir2){
				if(dis[xx][yy][dir2] > dis[x][y][pre_dir]+((pre_dir^dir)&1)+((dir^dir2)&1)){
					dis[xx][yy][dir2] = dis[x][y][pre_dir]+((pre_dir^dir)&1)+((dir^dir2)&1);
					if(!gph[xx][yy]){
						push(xx,yy,dir2);
						if(tail==MAXQ)	tail=0;
					}
				}
			}
		}
	}
	
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if((i^x0)||(j^y0))
				if(gph[i][j]==gph[x0][y0]&&(dis[i][j][0]<3||dis[i][j][1]<3||dis[i][j][2]<3||dis[i][j][3]<3))
					++cnt[x0][y0];
}

int main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%d",&gph[i][j]);
	
	for(int i=1;i<=n;++i)
		for(register int j=1;j<=m;++j)
			bfs(i,j);
	
	for(int i=1;i<=n;++i)
		for(register int j=1;j<=m;++j)
			printf("%d%c",cnt[i][j],j==m?'\n':' ');
	return 0;
}

T2:

题面:遍历树上的所有节点,求最短路径

思路:显然可以有一条路径只走一遍,其他的都要走两遍,只走一遍的选直径肯定最优,注意1e6可能卡栈空间,bfs就好了

代码:

#include<bits/stdc++.h>
#define MAXN 1000005
using namespace std;	int n;

int root;

struct t1{
	int to,nxt,lth;
}edge[MAXN<<1];	int cnt_edge;
int fst[MAXN];
void addedge(int x,int y,int lth){
	edge[++cnt_edge].to=y;
	edge[cnt_edge].nxt=fst[x];
	edge[cnt_edge].lth=lth;
	fst[x]=cnt_edge;
	
	edge[++cnt_edge].to=x;
	edge[cnt_edge].nxt=fst[y];
	edge[cnt_edge].lth=lth;
	fst[y]=cnt_edge;
}

long long dis[MAXN];
int fth[MAXN];

int que[MAXN<<1],head,tail;
int bfs(int now){
	int rtn = now;
	
	head=tail=0;
	memset(fth,0,sizeof fth);
	
	dis[now]=0;
	
	que[tail++]=now;
	while(head^tail){
		now=que[head++];
		for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
			int aim=edge[tmp].to;
			if(aim==fth[now])	continue;
			fth[aim] = now;
			dis[aim] = dis[now] + edge[tmp].lth;
			if(dis[aim] > dis[rtn])	rtn = aim;
			que[tail++]=aim;
		}
	}
	return rtn;
}

long long ans=0;

int read_x,read_y,read_lth;
int main(){
	freopen("journey.in","r",stdin);
	freopen("journey.out","w",stdout);
	
	srand(20000218);
	
	scanf("%d",&n);
	root=rand()%n+1;
	
	for(int i=1;i<n;++i)
		scanf("%d%d%d",&read_x,&read_y,&read_lth),
		ans += read_lth,
		addedge(read_x,read_y,read_lth);
	
	ans<<=1ll;
	root=bfs(root);
	int r2=bfs(root);
	printf("%lld",ans - dis[r2]);
	
	return 0;
}

T3:

题面:

一条路长度为D,从起点走到终点,每秒会减少A的血量(0.1秒减少0.1A的那种方式),在每一整秒的末尾可以增加一定血量,如果在任一瞬间血量小于0就失败。每获得1的初始血量需要G1的代价,每获得1的速度需要G2的代价(速度必须小于等于D),每获得1的回复量需要G3的代价,求最小花费。D和A都是1e6的,G1 G2 G3都是200的。

思路:

显然推公式,枚举速度v的取值,如果选初始血量比回复更优,肯定就全部氪在G1上,初始血量氪(ceil(A*D/v)),如果回复更优,肯定初始血量就是A,之后每秒回复也是A,对于每个速度直接把上面那两个值取min就好了,根本不需要什么分类讨论【果然还是我菜了233333】

注意因为血是每秒递减的,所以上取整操作要对(A*(D/v))整个进行

代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;	long long A,D,G1,G2,G3;

int main(){
	freopen("run.in","r",stdin);
	freopen("run.out","w",stdout);
	
	scanf("%lld%lld%lld%lld%lld",&D,&A,&G1,&G2,&G3);

	long long ans=INF;
	
	long long tt=A*G1+A*G3;
	for(int b=1;b<=D;++b)
		ans=min(ans,b*G2+min(tt,(long long)(ceil((double)A*D/b)*G1)));
	
	printf("%lld",ans);
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值