hgoi#20191114
作者:互联网
T1-宇宙魔方
有一个 \(n^3\) 的立方体,每次会给这个立方体的一层都加上 \(X\) 或整体转动这个立方体
现在给你若干次操作后的立方体,有一个格子上的值不知道,请你求出
解法
直接模拟回溯所有的操作
具体是每次找到一层的最小值
全部减去即可
ac代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
inline void read(int&x)
{
x=0;int fh=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')fh=-1;
for(;isdigit(c);c=getchar())x=x*10+c-'0';
x*=fh;
}
inline void print(int x)
{
if(x>9)print(x/10);
putchar(x%10+'0');
}
int n,minn,a[110][110][110];
int main()
{
freopen("cube.in","r",stdin);
freopen("cube.out","w",stdout);
read(n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
read(a[i][j][k]);
for(int i=1;i<=n;i++)
{
minn=inf;
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(a[i][j][k]>=0)
minn=min(minn,a[i][j][k]);
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
a[i][j][k]-=minn;
minn=inf;
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(a[j][i][k]>=0)
minn=min(minn,a[j][i][k]);
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
a[j][i][k]-=minn;
minn=inf;
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(a[j][k][i]>=0)
minn=min(minn,a[j][k][i]);
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
a[j][k][i]-=minn;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(a[i][j][k]<0)
print(-a[i][j][k]-1);
fclose(stdin);
fclose(stdout);
return 0;
}
T2-战争
给你一个带权无向图,要求你每次走的边权都要严格递增
求最远能走的距离
解法
这个根本不用建图
令 \(f_{i,j}\) 表示 \(i\) 号点作为终点,上一个走的权值为 \(j\) 的最远距离
我们发现一条边只会更新两个点,所以把第二维压掉
具体见代码
ac代码
#include<bits/stdc++.h>
using namespace std;
inline void read(int&x)
{
x=0;int fh=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')fh=-1;
for(;isdigit(c);c=getchar())x=x*10+c-'0';
x*=fh;
}
inline void print(int x)
{
if(x>9)print(x/10);
putchar(x%10+'0');
}
struct node
{
int x,y,s;
void init(){read(x),read(y),read(s);}
bool operator<(const node&a)const{return s<a.s;}
}e[50010];
queue<int>q;
int n,m,ans,f[50010],g[50010];
int main()
{
freopen("war.in","r",stdin);
freopen("war.out","w",stdout);
read(n),read(m);
for(int i=1;i<=m;i++)e[i].init();
sort(e+1,e+m+1);
int nw=1,ed=1;
while(nw<=m)
{
while(ed<m&&e[ed].s==e[ed+1].s)ed++;
while(nw<=ed)
{
g[e[nw].x]=max(g[e[nw].x],max(f[e[nw].x],f[e[nw].y]+1));
g[e[nw].y]=max(g[e[nw].y],max(f[e[nw].y],f[e[nw].x]+1));
q.push(e[nw].x),q.push(e[nw].y),nw++;
}ed++;
while(!q.empty())f[q.front()]=g[q.front()],q.pop();
}
for(int i=0;i<n;i++)ans=max(ans,f[i]);print(ans);
fclose(stdin);
fclose(stdout);
return 0;
}
T3-和平
给你一棵带边权的树,若干次询问
每次询问 \(A、B、c\) 表示从A出发,走到B,只能通过边权大于等于 \(c\) 的点
求最多能走到哪里
解法
先拆成两部分,先从 \(A\) 走到 \(LCA\) ,再从 \(LCA\) 走到 \(B\)
如果停下的地方在第一部分,用倍增非常好做
但是如果停下的地方在第二部分怎么办呢
我们可以二分求这条路径的断点,然后求出一段的最小值,看是否符合要求
具体实现见代码
ac代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mid (l+r>>1)
#define pb push_back
#define N 100010
#define K 18
using namespace std;
inline void read(int&x)
{
x=0;int fh=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')fh=-1;
for(;isdigit(c);c=getchar())x=x*10+c-'0';
x*=fh;
}
inline void print(int x)
{
if(x>9)print(x/10);
putchar(x%10+'0');
}
vector<int>e[N],w[N];
int n,m,x,y,z,d[N],f[N][K],v[N][K];
void dfs(int u,int fa)
{
int sz=e[u].size();
for(int i=0;i<sz;++i)if(e[u][i]!=fa)
f[e[u][i]][0]=u,v[e[u][i]][0]=w[u][i],
d[e[u][i]]=d[u]+1,dfs(e[u][i],u);
}
inline int lca(int x,int y)
{
if(d[x]<d[y])swap(x,y);
if(d[x]>d[y])
{
int g=d[x]-d[y];
for(int i=0;i<K;++i)
if(g&(1<<i))
x=f[x][i];
}
if(x==y)return x;
for(int i=K-1;i>=0;--i)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline int get(int u,int g)
{
int ans=inf;
for(int i=0;i<K;++i)
if(g&(1<<i))
ans=min(ans,v[u][i]),
u=f[u][i];
return ans;
}
//得到u向上g条边的最小值
inline int find(int u,int g)
{
for(int i=0;i<K;++i)
if(g&(1<<i))
u=f[u][i];
return u;
}
//寻找u向上g条边的点
inline int query(int st,int ed,int G)
{
int LCA=lca(st,ed),da=d[st]-d[LCA],db=d[ed]-d[LCA];
int l=0,r=da+db,ans,D=get(st,da);
while(l<=r)
if((mid<=da?get(st,mid):min(D,get(find(ed,da+db-mid),mid-da)))<G)r=mid-1;else ans=mid,l=mid+1;
//二分这个断点,如果在第一部分,那么路径只有一段
//如果在第二部分,分成整个第一部分和第二部分断点上方的位置求解
if(ans>da)return find(ed,da+db-ans);else return find(st,ans);
}
int main()
{
freopen("peace.in","r",stdin);
freopen("peace.out","w",stdout);
read(n),read(m);
for(int i=1;i<n;i++)
read(x),read(y),read(z),
e[x].pb(y),w[x].pb(z),
e[y].pb(x),w[y].pb(z);
dfs(1,0);
for(int j=1;j<K;++j)
for(int i=1;i<=n;++i)
f[i][j]=f[f[i][j-1]][j-1],
v[i][j]=min(v[i][j-1],v[f[i][j-1]][j-1]);
for(int i=1;i<=m;++i)
read(x),read(y),read(z),
print(query(x,y,z)),putchar('\n');
fclose(stdin);
fclose(stdout);
return 0;
}
标签:10,int,20191114,void,read,fh,hgoi,getchar 来源: https://www.cnblogs.com/muronglin/p/hgoi-20191114.html