三牧校内训练20220126题解

A
送分题,不多说了。

#include<iostream>
using namespace std;
int main()
{
  int sum=0;
  int k,s=0;
  cin>>k;
  for(int i=1;;i++)
    for(int j=1;j<=i;j++)
    {
      sum=sum+i;s++;
      if(s==k)
      {
        cout<<sum<<endl;
        return 0;
      }
    }
  return 0;
}

 



B
直接DFS/BFS判连通块即可。

#include<iostream>
using namespace std;
const int dx[4]={-1, 1, 0, 0};
const int dy[4]={ 0, 0,-1, 1};
char map[1010][1010];
int R,C,c[1010][1010],sum,ans=0;
void floodfill(int x,int y,int color)
{
  for(int i=0;i<4;i++)
  {
    int tx=x+dx[i];
    int ty=y+dy[i];
    if(x<1||x>R||y<1||y>C)continue;
    if(!c[tx][ty]&&map[tx][ty]=='#')
    {
      sum++;
      c[tx][ty]=color;
      floodfill(tx,ty,color);
    }
  }
}
bool crash(int x,int y,int color)
{
  int i,j,w=0,l=0;
  i=x,j=y;while(c[i][j]==color)i++,w++;
  i=x,j=y;while(c[i][j]==color)j++,l++;
  if(w*l==sum)ans++;
  return w*l!=sum;
}
int main()
{
  cin>>R>>C;
  for(int i=1;i<=R;i++)
    for(int j=1;j<=C;j++)
      cin>>map[i][j];

  int color=0;
  for(int i=1;i<=R;i++)
  for(int j=1;j<=C;j++)
  if(!c[i][j]&&map[i][j]=='#')
  {
    sum=0;
    floodfill(i,j,++color);
    if(crash(i,j,color))
    {
      cout<<"Bad placement."<<endl;
      return 0;
    }
  }
  cout<<"There are "<<ans<<" ships."<<endl;
  return 0;
}

 

C

把不同楼层的图按起终点连起来成为一张大图做最短路即可。注意结点标号。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
int n[110],m[110],S[110],T[110],vis[110][2010],dis[110][2010];
int H,K,s[110],h[110][1010],p[110][2010],t[110][2010],w[110][2010];
void adde(int a,int u,int v,int x){
  p[a][++s[a]]=h[a][u],t[a][s[a]]=v,w[a][s[a]]=x,h[a][u]=s[a];
}
int spfa(int a){//spfa=dijkstra
  priority_queue<pair<int,int> >pq;
  for(int i=1;i<=n[a];i++)dis[a][i]=0x3f3f3f3f;
  dis[a][S[a]]=0;pq.push(make_pair(0,S[a]));
  while(!pq.empty()){
    int u=pq.top().second;pq.pop();
    if(vis[a][u])continue;vis[a][u]=true;
    for(int i=h[a][u];i;i=p[a][i]){
      int v=t[a][i];
      if(dis[a][v]>dis[a][u]+w[a][i]){
        dis[a][v]=dis[a][u]+w[a][i];
        if(!vis[a][v])pq.push(make_pair(-dis[a][v],v));
      }
    }
  }
  return dis[a][T[a]];
}
int main(){
  int sum=0,ans[110];   scanf("%d%d",&H,&K);   for(int i=1;i<=H;i++){   scanf("%d%d%d%d",n+i,m+i,S+i,T+i);     for(int j=1;j<=m[i];j++){       int a,b,c;scanf("%d%d%d",&a,&b,&c);       adde(i,a,b,c);adde(i,b,a,c);     }     ans[i]=spfa(i);   }   sort(ans+1,ans+H+1);   for(int i=1;i<=H-K;i++)sum+=ans[i];   return !printf("%d",sum); }

 

D

下设 $son(u)$ 为的所有孩子组成的结点集合。以下设的状态都在以 $u$ 为根的子树内进行。

对于 $k=1$ 的情况,设 $f_u$ 表示选取 $u$ 的最大值,$g_u$ 为选取 **任意** $v\in son(u)$ 的最大值。

显然,$f_u=\sum_{v\in son(u)}\limits g_v$, $g_u=\sum_{v\in son(u)}\limits \max\{f_v,g_v\}$。最后答案为 $\max\{f_1, g_1\}$ 。

下面讨论 $k=2$ 的情况。设 $f_u$ 表示选取 $u$ 的最大值,为选取 **至多一个** $v\in son(u)$ 的最大值,$h_u$ 为选取范围在 $\{v|v\neq u\text{ and }v\notin son(u)\}$ 内的最大值。

显然$f_u=\sum_{v\in son(u)}\limits h_v$ ,$h_u=\sum_{v\in son(u)}\limits g_v$,(据定义非常容易得到)。

那么怎么计算呢?我们知道不能选取 $u$ 的超过1个孩子(因为距离为2),但是选择 $v\in son(u)$ 的孩子和的 $u$ 的孩子是可以的。

而且选择 $v\in son(u)$ 和 $u$ 的另一个孩子的孩子也是可以的。在这两个里面取一个max即可。

最后答案为\max\{f_1,g_1,h_1\}。时间复杂度均为 $\Theta(n)$。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define ll long long
#define mxn 100010
#define mxm 200010
using namespace std;
template<class T>T cmin(T a,T b){return a<b?a:b;}
template<class T>T cmax(T a,T b){return a>b?a:b;}
int n,k,s,hd[mxn],p[mxm],t[mxm];int f[mxn],g[mxn],h[mxn];
void adde(int u,int v){p[++s]=hd[u],t[s]=v,hd[u]=s;}
void dfs(int u,int fa){f[u]=1,g[u]=h[u]=0;
  for(int i=hd[u];i;i=p[i]){int v=t[i];if(v==fa)continue;
    dfs(v,u);if(k==1){f[u]+=g[v];g[u]+=cmax(f[v],g[v]);}
    else{f[u]+=h[v];g[u]=cmax(g[u]+g[v],h[u]+f[v]);h[u]+=g[v];}
  }
}
signed main(){scanf("%d%d",&n,&k);
  for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);adde(u,v);adde(v,u);}
  dfs(1,0);return !printf("%d\n",cmax(cmax(f[1],g[1]),h[1]));
}

 

posted @ 2022-01-20 22:58  Remained_Apple  阅读(68)  评论(0)    收藏  举报