2020牛客寒假算法基础集训营3
题目链接:https://ac.nowcoder.com/acm/contest/3004
假算法集训营第3期,快来看看你有哪些基础知识还不会吧!~
这几天有时间先补图论的坑,再补LCT吧,字符串和几何目前只能选择相信队友。
A - 牛牛的DRB迷宫I
水题
F - 牛牛的Link Power I
G题的不带修形式。甚至从这道题已经可以知道下一道题的线段树要怎么维护了。
题意:有一个01串,求每对1之间的距离和。
题解:每右移一位,总的距离就增加左侧的1的数量。在遇到1的时候统计“它作为右边的1时”的贡献。
char g[100005];
void test_case() {
int n;
scanf("%d%s", &n, g + 1);
ll ans = 0, sum = 0;
int cnt = 0;
for(int i = 1; i <= n; ++i) {
if(g[i] == '1') {
ans += sum;
++cnt;
}
sum += cnt;
if(sum >= MOD)
sum -= MOD;
}
ans %= MOD;
printf("%lld\n", ans);
}
H - 牛牛的k合因子数
题意:给一个n<=1e5,求范围中有多少个数恰好有k个合数因子。
题解:由于 \(\sum\limits_{i=1}^{n}\lfloor\frac{n}{i}\rfloor ~ O(nlogn)\) ,直接暴力求。
const int MAXN = 1e5;
int p[MAXN + 5], ptop;
bool pn[MAXN + 5];
void sieve() {
int n = MAXN;
pn[1] = 1;
for(int i = 2; i <= n; i++) {
if(!pn[i])
p[++ptop] = i;
for(int j = 1; j <= ptop; j++) {
int t = i * p[j];
if(t > n)
break;
pn[t] = 1;
if(i % p[j] == 0)
break;
}
}
}
int cnt[MAXN + 5];
int ans[MAXN + 5];
void test_case() {
sieve();
int n, m;
scanf("%d%d", &n, &m);
for(int i = 2; i <= n; ++i) {
if(pn[i]) {
for(int j = i; j <= n; j += i)
++cnt[j];
}
}
for(int i = 1; i <= n; ++i)
++ans[cnt[i]];
while(m--) {
int k;
scanf("%d", &k);
printf("%d\n", ans[k]);
}
}
*D - 牛牛与二叉树的数组存储
一开始觉得:“什么垃圾题,怎么花钱买了这种题。”
然后就段错误了。事实证明不能够小看和轻视。
题意:给一棵满二叉树,上面恰好有[1,m]号节点,按顺序输出他们的父亲和孩子们。
题解:模拟,然后小心越界。
int data[200005], pos[200005];
void test_case() {
int n, m = 0;
scanf("%d", &n);
memset(data, -1, sizeof(data));
for(int i = 1; i <= n; ++i) {
scanf("%d", &data[i]);
if(data[i] != -1) {
pos[data[i]] = i;
m = max(m, data[i]);
}
}
printf("The size of the tree is %d\n", m);
printf("Node %d is the root node of the tree\n", data[1]);
for(int i = 1; i <= m; ++i)
printf("The father of node %d is %d, the left child is %d, and the right child is %d\n", i, data[pos[i] / 2], data[pos[i] * 2], data[pos[i] * 2 + 1]);
}
*C - 牛的数组越位
题意:告诉你C++中二维数组中中括号的运算规则,以及某编译器对此ub的处理。要求模拟给数组赋值,检测是否有ub甚至真正的re。
题解:按题意模拟。
总结:没写过这种**bug就不知道自己这么**,居然连
if(0 <= x < n)
statement;
这种表达都出来了。其实编译器已经给出了警告,记得在新电脑上调好编译器并打开 -Wall 开关。
KisekiPurin.cpp|69|warning: comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses]|
int a[1000005];
void test_case() {
int n, m, p;
scanf("%d%d%d", &n, &m, &p);
memset(a, 0, sizeof(a[0]) * (n * m));
bool ub = 0, re = 0;
while(p--) {
int x, y, v;
scanf("%d%d%d", &x, &y, &v);
if(re)
continue;
ll t = 1ll * x * m + y;
if(0 <= x && x < n) {
if(0 <= y && y < m)
a[t] = v;
else {
ub = 1;
if(0 <= t && t < n * m)
a[t] = v;
else
re = 1;
}
} else {
ub = 1;
if(0 <= t && t < n * m)
a[t] = v;
else
re = 1;
}
}
if(re) {
puts("Runtime error");
return;
}
int top = 0;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j)
printf("%d%c", a[top++], " \n"[j == m - 1]);
}
if(ub)
puts("Undefined Behaviour");
else
puts("Accepted");
}