A - 推断上下级
HihoCoder - 1947
H公司包括CEO在内,一共有N名员工,编号1~N,其中CEO的编号是1。除了CEO之外,其他员工都有唯一一名直接上司,形成了一种树形的上下级关系。
现在小Hi知道H公司所有的上下级关系,一共M对。换句话说,只要两名员工A和B之间存在上下级关系(直接或者间接),那么A和B一定在这M对关系之中。
请你帮小Hi推断出每个人的直接上级是谁。
从题面可以看出,M对关系所构成的关系图不包含环,所以按入度拓扑排序可得到每个人的直接上级。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e5+100;
vector <int> f[maxn];
int n,m;
int indegree[maxn];
int fa[maxn];
void topo(int n){
int i,j,id,t=0;
for(j=1;j<=n;j++){
for(i=1;i<=n;i++){
if(indegree[i]==0){
id=i;
break;
}
}
indegree[id]=-1;
for(int i=0;i<f[id].size();i++){
int k=f[id][i];
fa[k] = id;
indegree[k]--;
}
}
}
int x,y;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
f[x].push_back(y);
indegree[y]++;
}
topo(n);
for(int i=1;i<=n;i++)
{
printf("%d\n",fa[i]);
}
return 0;
}
B - H市规划
HihoCoder - 1949
H市的平面地图可以看成是一个NxM的方格矩阵,每一个格子代表H市的一个区域。
H市的市长给每一个方格都标记了一个0~2的数字,2代表该区域包含高校,1代表该区域包含创业园,0代表该区域既不包含高校也不包含创业园。(没有区域既包含高校也包含创业园)
现在H市长希望选出一片连续的区域(若干上下左右连在一起的方格)进行特别规划,要求
1)这片区域需要既包含高校也要包含创业园
2)这片区域面积尽量小,即包含方格的数目尽量少
请你帮H市长找出满足条件的一片区域,并且输出其包含方格的数目。
看起来像是类似平面上最近点对,可以考虑分治做法,把整个平面分成两块,最后在统计黑白两点分别在两块的情况。 (类比平面上最近的点对)
不过这道题数据有点弱,只要加几个特判的暴力就能卡过(甚至不加特判的暴力)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1e6+100;
int f[1010][1010];
char s[1010][1010];
int cnt1,cnt2;
struct node
{
int x,y,id;
};
node f1[maxn],f2[maxn];
int jump[1010],n,m;
bool cmp(node a,node b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
}
int ans= 1e9;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s[i][j]=='1') f1[++cnt1].x=i,f1[cnt1].y=j,jump[i]++;
if(s[i][j]=='2') f2[++cnt2].x=i,f2[cnt2].y=j;
if(s[i][j]=='1'&&s[i-1][j]=='2') ans=2;
if(s[i][j]=='1'&&s[i][j-1]=='2') ans=2;
if(s[i][j]=='1'&&s[i+1][j]=='2') ans=2;
if(s[i][j]=='1'&&s[i][j+1]=='2') ans=2;
}
}
if(ans==2){
cout<<2<<endl;
return 0;
}
for(int i=1;i<=cnt1;i++)
{
for(int j=1;j<=cnt2;j++)
{
ans=min(ans,abs(f1[i].x-f2[j].x)+abs(f1[i].y-f2[j].y)+1);
}
}
cout<<ans<<endl;
return 0;
}
C - 二叉树
HihoCoder - 1951
给出一棵n个点的二叉树,所有节点从1到n编号,根节点的编号为1。
你需要给每个点标记0或者1。标记结束后,按照二叉树的先序遍历把标记写下,可以得到一个二进制数a(可能有前导0)。同样后序遍历也可以得到一个二进制数b。
求所有标号中,a-b的最大值。
求出先序遍历和后序遍历,我们考虑如何使先序遍历所代表的二进制数比后续大。 对于每一个节点如果其在先序中比在后序中靠前 - 此时让其等于1先序和后序的差值会变大 , 同理如果其在后序中的位置考前,再让其等于1会使后序变大,所以这种情况我们让其等于零。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#define LL long long
using namespace std;
const int maxn = 1e5+100;
const LL mod = 998244353;
int n;
struct node
{
int ls,rs;
};
node T[maxn];
int h1[maxn],h2[maxn];
int a1[maxn],a2[maxn];
int cnt1,cnt2;
map <int,int > mp;
void dfs_frt(int u)
{
h1[++cnt1] = u;
if(T[u].ls) dfs_frt(T[u].ls);
if(T[u].rs) dfs_frt(T[u].rs);
}
void dfs_bck(int u)
{
if(T[u].ls) dfs_bck(T[u].ls);
if(T[u].rs) dfs_bck(T[u].rs);
h2[++cnt2] = u;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>T[i].ls>>T[i].rs;
}
dfs_frt(1);
dfs_bck(1);
//for(int i=1;i<=n;i++) cout<<h1[i]<<" "<<h2[i]<<endl;
for(int i=1;i<=n;i++)
{
mp[h2[i]] = i;
}
for(int i=1;i<=n;i++)
{
int u = mp[h1[i]];
if(u<=i) a1[i] = 0 , a2[u] = 0;
else a1[i] = 1, a2[u] =1;
}
LL r1=0,r2=0;
for(int i=1;i<=n;i++)
{
if(a1[i]) r1=r1*2+1;
else r1*=2;
r1%=mod;
if(a2[i]) r2=r2*2+1;
else r2*=2;
r2%=mod;
}
r1-=r2;
while(r1<0) r1+=mod;
cout<<r1<<endl;
return 0;
}
F - 数组划分游戏
HihoCoder - 1948
小Hi在玩一个有关数组划分的游戏。给定一个整数K和一个长度为N的数组A=[A1, A2, … AN],小Hi需要将它划分为K个连续子数组,并对每个子数组求和。
不妨设这K个子数组的和依次是S1, S2, … SK,则小Hi的得分是其中的最小值即min(S1, S2, … SK)。
例如对于A=[1, 2, 3, 4]和K=2,小Hi可以划分成[1, 2]和[3, 4],这样得分是3;也可以划分成[1, 2, 3]和[4],这样得分是4。
对于给定的K和数组A,你能帮助小Hi算出他最多能得多少分吗?
F题竟然是最简单的题,从题面不难看出最小值最大很明显是二分,答案具有单调性,因为最小值越大划分次数越少。(数组元素都大于0)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#define LL long long
using namespace std;
const int maxn = 1e5+100;
const LL mod = 998244353;
int n,k;
LL a[maxn] ,l,r,ans;
bool check(LL val)
{
LL res=0,cnt=0;
for(int i=1;i<=n;i++)
{
res+=a[i];
if(res>=val)
{
res=0;
cnt++;
if(cnt==k) return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
r+=a[i];
}
while(l<=r)
{
LL mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
cout<<ans<<endl;
return 0;
}