三牧校内训练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])); }

浙公网安备 33010602011771号