今天已经是最后一次模拟考试了,虽然成绩不尽人意,但也无力更改,希望在接下来的 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)! (n−2)!,还有 10 p t s 10pts 10pts是 L R LR LR交替,是没有方案的,所以输出 0 0 0。
正解因为时间紧迫就只能先鸽了。