NC月赛补题
Posted k2mno4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NC月赛补题相关的知识,希望对你有一定的参考价值。
NC月赛补题
B-树上子链:
题目描述
给定一棵树 T ,树 T 上每个点都有一个权值。
定义一颗树的子链的大小为:这个子链上所有结点的权值和 。
请在树 T 中找出一条最大的子链并输出。
输入描述:
第一行输入一个 n,1≤n≤10^5。
接下来一行包含n个数,对于每个数ai,-10^5 <= ai <= 10^5,表示 i 结点的权值。
接下来有n-1行,每一行包含两个数u,v( 1 <= u,v <= n,u != v),表示u与v之间有一条边。
输出描述:
仅包含一个数,表示我们所需要的答案。
示例1
输入
5
2 -1 -1 -2 3
1 2
2 3
2 4
2 5
输出
4
说明
样例中最大子链为1 -> 2 -> 5
备注:
一个结点,也可以称作一条链
ps: 巨坑的long long型,不会的图论的我死磕,赶紧学习一波存图再说吧,不过还是感谢某巨佬耐心指导。(以后总结图论)这题和树的直径类似...
AC:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 7;
const int maxm = 2e5 + 7;
const long long mod = 1e9 + 7;
const long long INF = 0x3f3f3f3f;
LL n,a[maxn],u,v,dp[maxn],ans=-INF;
int vis[maxn];
vector<LL> G[maxn];
void dfs(LL x)
{
vis[x] = 1; //标记该点已经走过
LL tmp1 = a[x],tmp2 = a[x]; //tmp1为该节点最长链,tmp2为该节点次长链
for(int i = 0; i<G[x].size(); i++)
{
if(vis[G[x][i]]) //判断邻接点是否遍历过
continue;
dfs(G[x][i]); //如果未遍历过就先进行遍历
dp[x] = max(dp[x],dp[G[x][i]] + a[x]); //用dp来存当前该根节点最大权值
if(dp[G[x][i]] + a[x] > tmp1) //判断是否新的子链大于最长子链
{
tmp2 = tmp1; //将原来的最长子链变成第二长子链
tmp1 = dp[G[x][i]] + a[x];
}
else if(dp[G[x][i]] + a[x] > tmp2) //判断是否新的子链大于次长子链而不是最长子链
tmp2 = dp[G[x][i]] + a[x]; //更新次长子链
}
dp[x] = tmp1; //仅有一一个子节点
ans = max(ans,tmp1 + tmp2 -a[x]);//最长子链 + 次长子链 - 当前节点权值
}
int main()
{
scanf("%lld",&n);
for(int i = 1; i <= n; i++)
scanf("%lld",&a[i]);
for(int i = 1; i < n; i++)
{
scanf("%lld%lld",&u,&v);
G[u].push_back(v); //用邻接表的方式存图
G[v].push_back(u);
}
memset(vis,0,sizeof(vis));
dfs(1); //从第一个点开始遍历整个图
printf("%lld",ans);
return 0;
}
D-收集纸片:
题目描述
我们把房间按照笛卡尔坐标系进行建模之后,每个点就有了一个坐标。
假设现在房子里有些纸片需要被收集,收集完纸片你还要回归到原来的位置,你需要制定一个策略来使得自己行走的距离最短。
你只能沿着 x 轴或 y 轴方向移动,从位置 (i,j) 移动到相邻位置 (i+1,j),(i-1,j),(i,j+1) 或 (i,j-1) 距离增加 1。
输入描述:
在第一行中给出一个T, 1≤T≤10, 代表测试数据的组数 。
对于每组输入,在第一行中给出房间大小,第二行给出你的初始位置。
接下来给出一个正整数 n,1≤n≤10 代表纸片的个数。
接下来 n 行,每行一个坐标代表纸片的位置。
保证房间小于 20×20,纸片一定位于房间内。
输出描述:
对于每组输入,在一行中输出答案。
格式参见样例。
示例1
输入
1
10 10
1 1
4
2 3
5 5
9 4
6 5
输出
The shortest path has length 24
AC:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
const int maxm=2e5+7;
const int num=15;
const long long mod=1e9+7;
const long long INF=0x3f3f3f3f;
int minLen=INF;
int a,b,n;
int r,c,t;
int vis[num];
struct node
{
int x,y;
}pos[num];
void dfs(int x,int y,int nn,int step)
{
if(!nn)
{
step+=abs(x-r)+abs(y-c);
minLen=min(minLen,step);
return;
}
for(int k=1;k<=n;k++)
{
int xx=pos[k].x;
int yy=pos[k].y;
if(!vis[k])
{
step+=abs(xx-x)+abs(yy-y);
vis[k]=1;
dfs(xx,yy,nn-1,step);
step-=abs(xx-x)+abs(yy-y);
vis[k]=0;
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d%d",&a,&b,&r,&c,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&pos[i].x,&pos[i].y);
memset(vis,0,sizeof(vis));
dfs(r,c,n,0);
if(minLen<INF)
printf("The shortest path has length %d
",minLen);
else
printf("-1
");
}
return 0;
}
E-方块涂色(水题)
题目描述
一块矩形区域被划分为了n行m列的小方格,初始情况下这些方格都是未被上色的。
为了使得矩形看起来不是单一的色彩,现在挑选出r行c列格子并将挑选出的格子上色。
请计算上色完成后,未上色格子的数目。
输入描述:
多组输入
每组输入在一行中给出四个数字 n, m, r, c,含义如题所示。
数据保证有 1<= n, m <= 10^6, 1 <=r <= n, 1 <= c <= m.
输出描述:
每组输入输出一行代表答案。
示例1
输入
5 5 2 3
输出
6
AC:
#include<bits/stdc++.h>
using namespace std;
long long n,m,r,c;
int main()
{
while(~scanf("%lld%lld%lld%lld",&n,&m,&r,&c))
{
printf("%lld
",n*m-m*r-n*c+r*c);
}
return 0;
}
F-累乘数字(还是水题)
题目描述
我们知道将一个大于1的数乘以另一个大于1的数会使乘积大于任意一个乘数。
现在给出两个数字 n, d,你能否计算将n乘以d次100的结果。
输入描述:
多组输入
每组输入在一行中给出n,d,1≤n,d≤100。
输出描述:
每组输入输出一行代表答案。
示例1
输入
5 1
11 1
85 2
输出
500
1100
850000
AC:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
const int maxm=2e5+7;
const long long inf=0x3f3f3f3f;
const long long mod=1e9+7;
string n;
char a='0';
int d;
int main()
{
while(cin>>n>>d)
{
for(int i=0;i<d;i++)
{
n=n+a;
n=n+a;
}
cout<<n<<endl;
}
return 0;
}
//题解:
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, d;
while (cin >> n >> d){
cout << n;
for (int i = 1;i <= d; cout << "00", i++);
cout << endl;
}
return 0;
}
G-仓库选址(暴力枚举)
题目:
牛能在某小城有了固定的需求,为了节省送货的费用,他决定在小城里建一个仓库,但是他不知道选在哪里,可以使得花费最小。
给出一个m×n的矩阵,代表下一年小城里各个位置对货物的需求次数。我们定义花费为货车载货运输的距离,货车只能沿着水平或竖直方向行驶。
输入描述:
首先在一行中输入T , T≤10,代表测试数据的组数。
每组输入在第一行给出两个正整数n, m,1≤n,m≤100,分别代表矩阵的宽和高。
接下来m行,每行n个不超过1000的数字,代表矩阵里的元素。
输出描述:
每组输入在一行中输出答案。
示例1
输入
3
2 2
1 1
1 0
4 4
0 8 2 0
1 4 5 0
0 1 0 1
3 9 2 0
6 7
0 0 0 0 0 0
0 1 0 3 0 1
2 9 1 2 1 2
8 7 1 3 4 3
1 0 2 2 7 7
0 1 0 0 1 0
0 0 0 0 0 0
输出
2
55
162
备注:
送货时只能单次运输,若该位置需要3次,货车必须跑3次。
即使该位置需要被送货,我们仍然可以选择该位置作为仓库。
AC:
//O(n^2 * m^2)也能过...
#include<bits/stdc++.h>
using namespace std;
const int num=105;
int maze[num][num];
int t,n,m,ans;
int main()
{
scanf("%d",&t);
while(t--)
{
ans=0x3f3f3f3f;
scanf("%d%d",&m,&n);
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
scanf("%d",&maze[i][j]);
for(int x = 1;x <= n;x++)
{
for(int y = 1;y <= m;y++)
{
int sum = 0;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
sum += (abs(x - i) + abs(y - j)) * maze[i][j];
}
}
ans = min(sum,ans);
}
}
printf("%d
",ans);
}
return 0;
}
还有剩下的慢慢来吧~~~
以上是关于NC月赛补题的主要内容,如果未能解决你的问题,请参考以下文章