链接:https://ac.nowcoder.com/acm/contest/11455/J
来源:牛客网
题目描述
在一行中给出一个字符串,请判断是否满足A + B格式,如果满足,输出计算结果,否则输出"skipped"。
此处A,B均为大于等于0的整数,不保证数据没有前导零。
输入描述:
第一行输入一个n, 1 \le n \le 1000n,1≤n≤1000,代表测试数据的组数。
接下来n行,每行输入一个长度不超过10000的字符串。
输出描述:
对于每组输入,输出结果
示例1
输入
复制
4
2+2
1+2
+12
0+0
输出
复制
4
3
skipped
0
注意加法的特征,必须是一个加号,并且加号的两边都有数,最后用到高精度加起来就行
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
//#include <algorithm>
//#include <bits/stdc++.h>
using namespace std;
#define gt(x) x = read()
//#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
inline int read(int out = 0)
{
char c;
while((c=getchar()) < 48 || c > 57);
while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
return out;
}
const int N = 5010;
const int M = 35;
const int mod = 1e9 + 7;
const int PP = 131;
const double eps = 1e-10;
string str;
string calc(int l, int r){
if (l > r) return "*";
string str1 = "";
bool flag = false;
for (int i = l; i <= r; i ++){
int x = (str[i] - '0');
// cout << x << " " <<str[i] << endl;
if (x || flag){
str1 += str[i];
flag = true;
}
}
if (!flag) str1 = "0";
return str1;
}
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
signed main(){
// ios;
int n;
cin >> n;
while(n --){
cin >> str;
bool flag3 = false;
int cnt = 0;
for (int i = 0; i < str.size(); i ++){
if (str[i] == '+') cnt ++;
else if (str[i] >= '0' && str[i] <= '9') continue;
else flag3 = true;
}
if (flag3 || cnt >= 2 || cnt == 0) {
cout << "skipped" << endl;
continue;
}
// cout << str << endl;
for (int j = 0; j < str.size(); j ++){
// cout << str[j] << endl;
if (str[j] == '+'){
// flag3 = true;
//cout << j << endl;
string a = calc(0, j - 1);
string b = calc(j + 1, str.size() - 1);
if (a == "*" || b == "*") cout << "skipped" << endl;
else{
// cout << a << endl;
//cout << b << endl;
vector<int> A, B;
for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
auto C = add(A, B);
for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
cout << endl;
}
break;
}
}
//if (!flag3) cout << "skipped/" << endl;
}
return 0;
}
仓库选址
链接:https://ac.nowcoder.com/acm/contest/11455/G
来源:牛客网
题目描述
牛能在某小城有了固定的需求,为了节省送货的费用,他决定在小城里建一个仓库,但是他不知道选在哪里,可以使得花费最小。
给出一个m \times nm×n的矩阵,代表下一年小城里各个位置对货物的需求次数。我们定义花费为货车载货运输的距离,货车只能沿着水平或竖直方向行驶。
输入描述:
首先在一行中输入T , T \le 10T,T≤10,代表测试数据的组数。
每组输入在第一行给出两个正整数n, m, 1 \le n,m \le 100n,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次。
即使该位置需要被送货,我们仍然可以选择该位置作为仓库。
直接暴力枚举仓库的位置即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
//#include <vector>
//#include <algorithm>
//#include <bits/stdc++.h>
using namespace std;
#define gt(x) x = read()
#define int long long
//#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
inline int read(int out = 0)
{
char c;
while((c=getchar()) < 48 || c > 57);
while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
return out;
}
const int N = 110;
const int M = 35;
const int mod = 1e9 + 7;
const int PP = 131;
const double eps = 1e-10;
int a[N][N];
signed main(){
int T;
gt(T);
while(T --){
int n, m;
gt(m), gt(n);
for (int i = 1; i <= n; i ++){
for (int j = 1; j <= m; j ++){
scanf("%lld", &a[i][j]);
}
}
//cout << "------" << endl;
int ans = 0x7f7f7f7f;
for (int i = 1; i <= n; i ++){
for (int j = 1; j <= m; j ++){
int sum = 0;
for (int k = 1; k <= n; k ++){
for (int p = 1; p <= m; p ++){
sum += (a[k][p] * (abs(k - i) + abs(p - j)));
}
}
// cout << sum << "----" << endl;
ans = min(ans, sum);
}
}
cout << ans << endl;
}
return 0;
}
收集纸片
链接:https://ac.nowcoder.com/acm/contest/11455/D
来源:牛客网
题目描述
我们把房间按照笛卡尔坐标系进行建模之后,每个点就有了一个坐标。
假设现在房子里有些纸片需要被收集,收集完纸片你还要回归到原来的位置,你需要制定一个策略来使得自己行走的距离最短。
你只能沿着 x 轴或 y 轴方向移动,从位置 (i,j) 移动到相邻位置 (i+1,j),(i-1,j),(i,j+1) 或 (i,j-1) 距离增加 1。
输入描述:
在第一行中给出一个T, 1 \le T \le 10T,1≤T≤10, 代表测试数据的组数。
对于每组输入,在第一行中给出房间大小,第二行给出你的初始位置。
接下来给出一个正整数 n,1 \le n \le 10n,1≤n≤10 代表纸片的个数。
接下来 n 行,每行一个坐标代表纸片的位置。
保证房间小于 20 \times 2020×20,纸片一定位于房间内。
输出描述:
对于每组输入,在一行中输出答案。
格式参见样例。
示例1
输入
复制
1
10 10
1 1
4
2 3
5 5
9 4
6 5
输出
复制
The shortest path has length 24
纸片的数目很少,所以只需要爆搜出所有纸片的顺序,然后每种顺序求一个最小值即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
//#include <vector>
//#include <algorithm>
//#include <bits/stdc++.h>
using namespace std;
#define gt(x) x = read()
#define int long long
//#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
inline int read(int out = 0)
{
char c;
while((c=getchar()) < 48 || c > 57);
while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
return out;
}
const int N = 110;
const int M = 35;
const int mod = 1e9 + 7;
const int PP = 131;
const double eps = 1e-10;
struct Node{
int a, b;
}node[M];
int cnt;
bool st[N];
int state[N];
int ans;
int x, y;
int calc(){
int nowx = x;
int nowy = y;
int sum = 0;
for (int i = 0; i < cnt; i ++){
sum = sum + abs(node[state[i]].a - nowx) + abs(node[state[i]].b- nowy);
nowx = node[state[i]].a;
nowy = node[state[i]].b;
}
sum = sum + abs(nowx - x) + abs(nowy - y);
return sum;
}
void dfs(int u){
if (u == cnt){
int sum = calc();
ans = min(sum, ans);
return;
}
for (int i = 1; i <= cnt; i ++ )
if (!st[i])
{
state[u] = i;
st[i] = true;
dfs(u + 1);
state[u] = 0;
st[i] = false;
}
}
signed main(){
int T;
gt(T);
while(T --){
ans = 0x7f7f7f7f;
int n, m;
gt(n), gt(m);
cin >> x >> y;
cin >> cnt;
for (int i = 1; i <= cnt; i ++){
cin >> node[i].a >> node[i].b;
}
dfs(0);
printf("The shortest path has length %d\n", ans);
}
return 0;
}
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int N=12;
int a[N],b[N];
int k;
int ans,fi,si,tmp;
bool st[N];
void dfs(int x,int y,int u)
{
if(u>k)
{
tmp+=abs(x-fi)+abs(y-si);
//cout<< abs(x-fi)+abs(y-si) <<endl;
//cout<< fi << " " << si <<endl;
//cout<< x <<" "<<y<<"----"<<endl;
ans=min(ans,tmp);
tmp-=abs(x-fi)+abs(y-si);
//cout<< tmp <<endl;
return;
}
for(int i=1;i<=k;i++)
{
if(!st[i])
{
st[i]=true;
tmp+=abs(x-a[i])+abs(y-b[i]);
//cout<< tmp <<endl;
dfs(a[i],b[i],u+1);
st[i]=false;
tmp-=abs(x-a[i])+abs(y-b[i]);
//cout<< tmp <<endl;
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
ans=0x3f3f3f3f;
tmp=0;
int n,m;
cin>>n>>m;
cin>>fi>>si;
cin>>k;
a[0]=fi,b[0]=si;
memset(st,0,sizeof st);
for(int i=1;i<=k;i++)
scanf("%d%d",&a[i],&b[i]);
dfs(fi,si,1);
printf("The shortest path has length %d\n",ans);
}
return 0;
}
树上子链
链接:https://ac.nowcoder.com/acm/contest/11455/B
来源:牛客网
题目描述
给定一棵树 T ,树 T 上每个点都有一个权值。
定义一颗树的子链的大小为:这个子链上所有结点的权值和 。
请在树 T 中找出一条最大的子链并输出。
输入描述:
第一行输入一个 n,1 \le n \le 10^5n,1≤n≤10
5
。
接下来一行包含n个数,对于每个数 a_i, -10^5 \le a_i \le 10^5a
i
,−10
5
≤a
i
≤10
5
,表示 i 结点的权值。
接下来有n-1行,每一行包含两个数u,v( 1 \le u,v \le n1≤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
备注:
一个结点,也可以称作一条链
最长的子链即为求树的最长路径,求树的最长路径有两种方法,一种是按照链的中点,把两根链绑到一块,一种是先走到最远点,然后从这个和最远的点再走到最远的点
这里把两种方法的代码都给出
#include <iostream>
#include <cstring>
#include <cstdio>
//#include <vector>
//#include <algorithm>
//#include <bits/stdc++.h>
using namespace std;
#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
inline int read(int out = 0)
{
char c;
while((c=getchar()) < 48 || c > 57);
while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
return out;
}
const int N = 2e5 + 10;
const int M = 35;
const int mod = 1e9 + 7;
const int PP = 131;
const double eps = 1e-10;
int f[N];
int w[N];
int h[N], ne[N], e[N], idx;
bool st[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int ans;
void dfs(int u, int father){
f[u] = w[u];
// cout << u << endl;
//if (st[u]) return;
//st[u] = true;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs(j, u);
// if (f[j] > 0) f[u] += f[j];
// cout << j << " " << f[j] << " " << u << " " << f[u] << endl;
ans = max(ans, f[j] + f[u]);
f[u] = max(f[u], f[j] + w[u]);
}
// cout << u << "----------" << f[u] << endl;
ans = max(ans, f[u]);
return;
}
signed main(){
int n;
gt(n);
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++) scanf("%lld", &w[i]);
// for (int i = 1; i <= n; i ++) cout << w[i] << endl;
for (int i = 1; i < n; i ++){
int a, b;
gt(a), gt(b);
add(a, b), add(b, a);
}
ans = -0x7f7f7f7f;
dfs(1, -1);
cout << ans << endl;
return 0;
}
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1e5+10,M=2*N;
int h[N],e[M],ne[M],w[N],idx;
LL dist1[N],dist2[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
dist1[j]=dist1[u]+w[j];
dfs1(j,u);
}
}
void dfs2(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
dist2[j]=dist2[u]+w[j];
dfs2(j,u);
}
}
int main()
{
int n;
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dist1[1]=w[1];
dfs1(1,-1);
int u=0;
LL dis=-0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++) if(dist1[i]>dis) dis=dist1[i],u=i;
dist2[u]=w[u];
dfs2(u,-1);
int p=0;
dis=-0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++) if(dist2[i]>dis) dis=dist2[i],p=i;
cout<< dis <<endl;
return 0;
}
操作序列
链接:https://ac.nowcoder.com/acm/contest/11455/A
来源:牛客网
题目描述
给出一个长度无限的数列,初始全部为零,有三种操作:
增加操作:给下标为 tt 的数加 cc 。特别注意,如果在下标 [t-30,t+30][t−30,t+30] 内有不为零的数,增加操作无效。
削减操作:让数列中下标最小的不为零数变为零。
查询操作:查询数列中下标为 tt 的数字是多少。
输入描述:
第一行包含一个整数 N,1 \le N \le 10^6N,1≤N≤10
6
,表示操作总数。
随后 N 行,每行由两个数字或一个数字组成。
若一行中有两个数字,分别代表增加操作的 t,c 。
若一行中只有数字-1,执行削减操作。
若一行中只有一个不为 -1的数字,则代表查询操作的数字 t。
保证t,c均为非负整数且在整形范围内。
输出描述:
削减操作时,先输出该数字,再变为零
若序列元素全为零,则削减操作无效,此时输出 “skipped”
查询时,输出该位置上的数
示例1
输入
复制
7
140 1
120 2
100 3
120
100
-1
100
输出
复制
0
3
3
0
示例2
输入
复制
4
140 3
-1
140 1
-1
输出
复制
3
1
示例3
输入
复制
3
-1
-1
-1
输出
复制
skipped
skipped
skipped
操作序列
判断下一个是否有数字可以getchar()看是否可以读取到字符
map的一些常用操作
mp.count(i) i那个位置上是否有数
mp.empty()这个map是否是空的
mp.begin() -> second第一个有的数字
mp.erase(mp.begin());删除第一个数字
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
//#include <vector>
//#include <algorithm>
//#include <bits/stdc++.h>
using namespace std;
#define gt(x) x = read()
#define int long long
//#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
map<int, int> mp;
inline int read(int out = 0)
{
char c;
while((c=getchar()) < 48 || c > 57);
while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
return out;
}
const int N = 1e5 + 10;
const int M = 35;
const int mod = 1e9 + 7;
const int PP = 131;
const double eps = 1e-10;
signed main(){
int T;
gt(T);
while(T --){
int x, y;
char c;
cin >> x;
c = getchar();
if (c == ' '){
cin >> y;
bool flag = false;
for (int i = x - 30; i <= x + 30; i ++)
if (mp.count(i)) flag = true;
if (!flag) mp[x] = y;
continue;
}
if (x == -1){
if (mp.empty()) puts("skipped");
else {
printf("%d\n", mp.begin() -> second);
mp.erase(mp.begin());
}
}
else{
if (mp.count(x)) cout << mp[x] << endl;
else cout << "0" << endl;
}
}
return 0;
}