191114CSP模拟

今天已经是最后一次模拟考试了,虽然成绩不尽人意,但也无力更改,希望在接下来的 C S P CSP CSP考试中冲一下吧;

T1:金币

相较于联赛 T 1 T1 T1来说,这道题难了一点,但也不是不能很快做。

我们先肯定不能直接暴搜,需要先求出每个宝藏与另一个最近宝藏的距离,用迪杰跑一下即可,然后就从每个宝藏开始搜索即可。

代码:

#include<bits/stdc++.h>
#define ll long long
#define db double
#define re register
#define cs const
#define y1 Y1
#define x1 X1
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch;
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}
cs int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
priority_queue<pair<int,pair<int,int> > >q;
int n,k,t,R,G,B,lx,rx,road[505][505];
int sx,sy,xx[15],yy[15],cnt,ans;
int dis[15][505][505];
char ch[505];
bool vis[505][505];
void dij(int num,int x1,int y1)
{
	dis[num][x1][y1]=0;
	q.push(make_pair(0,make_pair(x1,y1)));
	while(!q.empty())
	{
		int x2=q.top().second.first;
		int y2=q.top().second.second;
		q.pop();
		if(vis[x2][y2]==num)	continue;
		vis[x2][y2]=num;
		for(re int i=0;i<4;++i)
		{
			int x3=x2+dir[i][0];
			int y3=y2+dir[i][1];
			if(x3>n||x3<1||y3>n||y3<1)	continue;
			if(dis[num][x3][y3]>dis[num][x2][y2]+road[x3][y3])
			{
				dis[num][x3][y3]=dis[num][x2][y2]+road[x3][y3];
				q.push(make_pair(-dis[num][x3][y3],make_pair(x3,y3)));
			}
		}
	}
}
bool mark[15];
void dfs(int pos,int step,int sum)
{
	if(step>=lx&&step<=rx)	ans=max(ans,step*t-sum);
	if(step==rx)	return;
	if(ans>=cnt*t-sum)	return;
	for(re int i=1;i<=cnt;++i)
	{
		if(mark[i])	continue;
		mark[i]=1;
		dfs(i,step+1,sum+dis[pos][xx[i]][yy[i]]);
		mark[i]=0;
	}
}
int main()
{
	n=read();
	k=read();
	t=read();
	lx=read();
	rx=read();
	R=read();
	G=read();
	B=read();
	for(re int i=1;i<=n;++i)
	{
		scanf("%s",ch+1);
		for(re int j=1;j<=n;++j)
		{
			if(ch[j]=='R')	road[i][j]=R;
			else if(ch[j]=='G')	road[i][j]=G;
			else if(ch[j]=='B')	road[i][j]=B;
			else if(ch[j]=='T')	xx[++cnt]=i,yy[cnt]=j;
			else if(ch[j]=='S')	road[i][j]=0,sx=i,sy=j;	
		}
	}
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0xff,sizeof(vis));
	dij(0,sx,sy);
	for(re int i=1;i<=cnt;++i)	dij(i,xx[i],yy[i]);
	dfs(0,0,0);
	printf("%d",ans);
}

T2:路径

其实部分分是很高的,但我只拿到了 40 p t s 40pts 40pts,有 30 p t s 30pts 30pts的树的直径不会求,还有 20 p t s 20pts 20pts的链求错了。

由于题目给出要求这棵无根树度数为 1 1 1的节点不超过 10 10 10个,所以我们可以把每个叶节点当做根建树跑一遍,这样就可以让我们的路径转化成序列,可以更好地操作。

然后由于是公共 g c d gcd gcd,所以每次减少至少 ÷ 2 ÷2 ÷2,所以只会有 l o g log log的改变的点,所以复杂度是 ( 10 n l o g V ) (10nlogV) (10nlogV)的。

我们每次 d f s dfs dfs时,从上往下扫,并且维护每个点到根节点的路径上的分界点即可。

代码:

#include<bits/stdc++.h>
#define int long long
#define db double
#define re register
#define cs const
#define pii pair<int,int>
#define mp make_pair
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch;
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}
cs int N=320005;
int tot,n,val[N],ans;
int first[N],net[N],to[N],du[N],num[N],fa[N],dep[N];
pii u[N][32];
int gcd(int a,int b)
{
	return !b?a:gcd(b,a%b);
}
void add(int x,int y)
{
	net[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
	++du[y];
	swap(x,y);
	net[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
	++du[y];
}
void dfs(int x,int fa)
{
	num[x]=0;
	dep[x]=dep[fa]+1;
	for(re int i=1;i<=num[fa];++i)
	{
		int now=u[fa][i].first;
		int last=u[fa][i].second;
		int gcc=gcd(last,val[x]);
		if(gcc!=u[x][num[x]].second)
		{
			u[x][++num[x]]=mp(now,gcc);
			ans=max(ans,gcc*(dep[x]-dep[now]+1));
		}
	}
	if(val[x]!=u[x][num[x]].second)
	{
		u[x][++num[x]]=mp(x,val[x]);
		ans=max(ans,val[x]);
	}
	for(re int e=first[x];e;e=net[e])
	{
		int v=to[e];
		if(v==fa)	continue;
		dfs(v,x);
	}
}
signed main()
{
	n=read();
	for(re int i=1;i<=n;++i)	val[i]=read();
	for(re int i=1;i<n;++i)		add(read(),read());
	for(re int i=1;i<=n;++i)	if(du[i]==1)	dfs(i,0);
	printf("%lld",ans);
}

T3:企鹅棋

这道题也有很多部分分,首先有 5 p t s 5pts 5pts的暴搜,如果写状压 d p dp dp就有 20 20 20,卡卡常就有 25 25 25,有 5 p t s 5pts 5pts是全为 B B B时,答案为 ( n − 2 ) ! (n-2)! (n2)!,还有 10 p t s 10pts 10pts L R LR LR交替,是没有方案的,所以输出 0 0 0

正解因为时间紧迫就只能先鸽了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值