您的位置:首页 > 理论基础 > 计算机网络

哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-低年级组)【solved:10 / 10】

2017-12-11 15:20 399 查看
A:不表

B:*max_element().

C:c语言上机题,计算一下函数式子或者说瞎看看位置即可。

#include <bits/stdc++.h>
using namespace std;

int main()
{
int n;
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n + i - 1; j++)
{
if(j <= n - i)   putchar(' ');
else putchar('*');
}
puts("");
}
}
return 0;
}


D:

枚举,枚举k*k矩形的左上角,这里有n×n种可能,然后每个矩形需要扫过每个位置,需要k×k次。所以复杂度O(n∗n∗k∗k)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50 + 5;
int ma[maxn][maxn];
int main()
{
int n, k;
while(~scanf("%d%d", &n, &k))
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
scanf("%d", &ma[i][j]);
}
}
int ans = 0;
for(int i = 1; i + k - 1 <= n; i++)
{
for(int j = 1; j + k - 1<= n; j++)
{
int temp = 0;
for(int x = i; x <= i + k - 1; x++)
{
for(int y = j; y <= j + k - 1; y++)
{
temp += ma[x][y];
}
}
ans = max(ans, temp);
}
}
printf("%d\n", ans);
}
return 0;
}


E:

数据弱,暴力枚举即可,从a枚举到b,然后把每个整数拆分即可,预处理0-9各有几个圈圈。有兴趣可以看看高年级组的数圈圈,数据是1e14就不能暴力了。

#include <bits/stdc++.h>
using namespace std;
int To[] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int a, b;
scanf("%d%d", &a, &b);
long long ans = 0;
for(int i = a; i <= b; i++)
{
int temp = i;
while(temp)
{
ans += To[temp % 10];
temp /= 10;
}
}
printf("%lld\n", ans);
}
return 0;
}


F:

看到a[i] - a[j] / i - j这个式子你们想到什么了吗,中学阶段根据两个点来求解这条线段的斜率是不是就这么求的,(y1−y2)/(x1−x2),那么我们把数组a看做是n个二维平面上的顶点即可,{x, y} = {数组下表,数组值}。显然这个n个顶点中求解最大斜率,必然是两个相邻的顶点,所以其实就等价于在原数组中找两两相邻的点中差值最大的值是多少。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200000 + 5;
pair<int, int> nodes[maxn];

int main()
{
int n;
while(~scanf("%d", &n))
{
for(int x = 0; x < n; x++)
{
int y;
scanf("%d", &y);
nodes[x] = {x, y};
}
double ans = -1e18;
for(int x = 0; x < n - 1; x++)
{
double k = (nodes[x+1].second - nodes[x].second) / (x+1 - x);
ans = max(ans, k);
}
printf("%.2f\n", ans);
}
return 0;
}


G:

搜索基础题。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500 + 5;
char ma[maxn][maxn];
int vis[maxn][maxn];
int n, m, sx, sy, gx, gy;
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
bool isInside(int x, int y)
{
return 0 <= x &&x < n && 0 <= y && y < m;
}
bool bfs()
{
memset(vis, 0, sizeof(vis));
queue<pair<int, int>>que;
que.push({sx, sy});

vis[sx][sy] = 1;
while(que.size())
{
pair<int, int> cur = que.front();que.pop();
if(cur.first == gx && cur.second == gy) return true;
for(int k = 0; k < 4; k++)
{
int fx = cur.first + dx[k];
int fy = cur.second + dy[k];
if(isInside(fx, fy) && vis[fx][fy] == 0 && ma[fx][fy] != '#')
{
vis[fx][fy] = 1;
que.push({fx, fy});
}
}
}
return false;
}

int main()
{
while(~scanf("%d%d", &n, &m))
{
for(int i = 0; i < n; i++)
{
scanf("%s", ma[i]);
for(int j = 0; j < m; j++)
{
if(ma[i][j] == 'S') sx = i, sy = j;
else if(ma[i][j] == 'E')    gx = i, gy = j;
}
}
if(bfs())   puts("Yes");
else puts("No");
}
return 0;
}


H:

如果只有一种物品{x,y}是不是答案就是x+y,现在有第二种物品{x,y},且记第一种物品的答案为sum1。那答案是不是就是x * sum1 + y * sum1 = (x + y) * sum1。现在有第三种物品{x,y},且记前两种物品答案为sum2,是不是答案就是(x + y) * sum2。同理。

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
int n;
while(~scanf("%d", &n))
{
long long ans = 1;
for(int i = 0; i < n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
ans = ans * (x + y) % mod;
}
printf("%lld\n", ans);
}
return 0;
}


I:

首先考虑这个区间最大为60,所以它能保存的答案是2^60,在longlong范围内,那么我们先提取出第一个区间{s[0], s[1], … s[k - 1]},把它算出来答案记录为temp,那么考虑到下一个区间{s[1], s[2], … s[k - 1], s[k]},两个区间只有s[0]和s[k]不一样,(要记住这个小技巧啊,以后经常会用的,减少计算量,如果每次重新计算区间,每次消耗的时间O(k),这样只有O(1)),那么我们只需要检查s[0]是否为1,如果为1,需要用temp减去它的贡献度,也就是(1LL << (k - 1)),得到的就是{s[1], s[2], …s[k - 1}。再把这个值*2,加上s[k]即可。

也就是说我们需要枚举每个区间的起点,一共有O(n)个,循环内的处理是一个O(1)的,所以一共的复杂度O(n)。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 6;
char s[maxn];

int main()
{
int T;
scanf("%d", &T);
for(int cas = 1; cas <= T; cas++)
{
int k;
scanf("%d", &k);
scanf("%s", s);
int len = strlen(s);
long long last = 0;
for(int i = 0; i < k; i++)
{
last = last * 2 + (s[i] - '0');
}
long long ans = last;
for(int i = k; i < len; i++)
{
if(s[i - k] == '1') last -= 1LL << (k - 1);
last = last * 2 + (s[i] - '0');
if(last > ans)  ans = last;
}
printf("Case #%d: %lld\n", cas, ans);
}
}


J:

爆搜,我们考虑复杂度,首先每次必然至少往前挪一步,所以挪步的状态共有L=20000。每个挪步的转移最多有n=2000种,所以所有的状态一共是n*L=四百万种,所以爆搜即可,我们先解决重复点的问题,因为是直接回满体力,所以同一个点我们只取花费钱最少的商店回复体力,所以我们可以通过排序,去重解决这个问题。在vector里面保存下来。然后转移的时候,每个状态记录记录为,{当前位置,剩余金钱,下一个到达的商店}。搜索即可。

希望这场比赛大家都能补完,上述所有题目应该都没有超过我们对你们大一的要求,最难的题目也只是搜索的基础题而已。另外希望你们通过本场比赛对计算时间复杂度有一定的概念,完成度不好的同学也不用心急,一场场比赛慢慢提高。一直心急怎么办,一直纠结自己不行,毫无益处,最好的解决办法就是完成所有作业习题,然后每场比赛对着给的题解完成补题。

#include <bits/stdc++.h>
using namespace std;
struct node
{
int pos, cost;
bool operator < (const node &other)const
{
if(pos != other.pos)    return pos < other.pos;
return cost < other.cost;
}
}nodes[2000 + 5];
struct travel
{
int pos, tot, nxt;
};

int n, L, strength, S;
vector<node>vec;

bool bfs()
{
int sz = vec.size();
queue<travel>que;
que.push({0, S, 0});

while(que.size())
{
travel cur = que.front();que.pop();

int lb = cur.pos, rb = cur.pos + strength;
if(rb >= L)
{
return true;
}
for(int i = cur.nxt; i < sz && lb <= vec[i].pos && vec[i].pos <= rb; i++)
{
if(cur.tot >= vec[i].cost)
{
que.push({vec[i].pos, cur.tot - vec[i].cost, i + 1});
}
}
}
return false;
}

int main()
{
while(~scanf("%d%d%d%d", &n, &L, &strength, &S))
{
for(int i = 0; i < n; i++)
{
int pos, cost;
scanf("%d%d", &pos, &cost);
nodes[i] = {pos, cost};
}
sort(nodes, nodes + n);
vec.clear();
for(int i = 0; i < n; i++)
{
if(i >= 1 && nodes[i - 1].pos == nodes[i].pos)   continue;
vec.push_back(nodes[i]);
}
if(bfs())   puts("Yes");
else puts("No");

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐