您的位置:首页 > 其它

2018年全国多校算法寒假训练营练习比赛(第五场)题解

2018-02-25 18:37 471 查看
题目链接

A - 逆序数

经典问题,有很多方法,例如树状数组,线段树,归并排序、分治等。代码不贴了。

B - Big Water Problem

单点修改求区间和,树状数组或者线段树都可以。

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

const int maxn = 1e5 + 10;
long long c[maxn];

int lowbit(int x) {
return x & (-x);
}

long long sum(int p) {
long long res = 0;
while(p) {
res += c[p];
p -= lowbit(p);
}
return res;
}

void update(int x, long long y) {
while(x < maxn) {
c[x] += y;
x += lowbit(x);
}
}

int main() {

int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
long long x;
scanf("%lld", &x);
update(i, x);
}
while(m --) {
int op;
scanf("%d", &op);
if(op == 1) {
int x;
long long y;
scanf("%d%lld", &x, &y);
update(x, y);
} else {
int L, R;
scanf("%d%d", &L, &R);
printf("%lld\n", sum(R) - sum(L - 1));
}
}
return 0;
}


C - 字符串的问题

比赛中暴力从大到小枚举前缀长度,KMP验证一下就 AC 了?还要思考一下复杂度究竟对不对。

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1000010;
int nx
;
char S
, T
;
int slen, tlen;

void getNext()
{
int j, k;
j = 0; k = -1; nx[0] = -1;
while(j < tlen)
if(k == -1 || T[j] == T[k])
nx[++j] = ++k;
else
k = nx[k];

}

/*
返回模式串在主串S中出现的次数
*/
int KMP_Count()
{
int ans = 0;
int i, j = 0;

if(slen == 1 && tlen == 1)
{
if(S[0] == T[0])
return 1;
else
return 0;
}
getNext();
for(i = 0; i < slen; i++)
{
while(j > 0 && S[i] != T[j])
j = nx[j];
if(S[i] == T[j])
j++;
if(j == tlen)
{
ans++;
j = nx[j];
}
}
return ans;
}

/*
int main()
{

int TT;
int i, cc;
cin>>TT;
while(TT--)
{
cin>>S>>T;
slen = strlen(S);
tlen = strlen(T);
cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl;
cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
}
return 0;
}
*/

int check(int x) {
int p1 = 0;
int p2 = slen - x;
while(p1 <= x - 1) {
if(S[p1] != S[p2]) return 0;
p1 ++;
p2 ++;
}

for(int i = 0; i < x; i ++) {
T[i] = S[i];
T[i + 1] = 0;
}

tlen = x;
if(KMP_Count() >= 3) return 1;
return 0;
}

int main() {
scanf("%s", S);
slen = strlen(S);
int ans = 0;
int L = 1, R = slen;
for(int i = slen - 1; i >= 1; i --) {
if(check(i)) {
ans = i;
break;
}
}
if(ans == 0) printf("Just a legend\n");
else {
for(int i = 0; i < ans; i ++) {
printf("%c", S[i]);
}
printf("\n");
}
}


D - 集合问题

写了一堆暴力模拟规则就搞过去了,看到有并查集AC的,有待学习。

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

const int maxn = 110000;
int n;
int A, B;
int a[maxn];
map<int, int> belong;
map<int, bool> flag;

int main() {
int fail = 0;
scanf("%d%d%d", &n, &A, &B);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
flag[a[i]] = 1;
}
sort(a + 1, a + 1 + n);
if(A == B) {
for(int i = 1; i <= n; i ++) {
if(flag[B - a[i]] == 0) {
fail = 1;
break;
}
belong[a[i]] = 2;
}
} else {
while(1) {
if(fail) break;
int ss = 0;
for(int i = 1; i <= n; i ++) {
if(belong[a[i]]) continue;
if(flag[A - a[i]] == 0 && flag[B - a[i]] == 0) {
fail = 1;
break;
} else if(flag[A - a[i]] == 1 && (flag[B - a[i]] == 0 || belong[B - a[i]])) {
if(belong[A - a[i]] == 2) {
fail = 1;
break;
}
belong[a[i]] = 1;
belong[A - a[i]] = 1;
ss = 1;
} else if((flag[A - a[i]] == 0 || belong[A - a[i]]) && flag[B - a[i]] == 1) {
if(belong[B - a[i]] == 1) {
fail = 1;
break;
}
belong[a[i]] = 2;
belong[B - a[i]] = 2;
ss = 1;
} else {
if(A - a[i] != a[i] && B - a[i] != a[i]) {
if(belong[A - a[i]] == 0 && belong[B - a[i]] == 0) {
continue;
} else if(belong[A - a[i]]) {
belong[a[i]] = belong[A - a[i]];
ss = 1;
} else {
belong[a[i]] = belong[B - a[i]];
ss = 1;
}
} else if(A - a[i] == a[i]) {
if(belong[B - a[i]] == 1) {
fail = 1;
break;
}
belong[a[i]] = 2;
belong[B - a[i]] = 2;
ss = 1;
} else {
if(belong[A - a[i]] == 2) {
fail = 1;
break;
}
belong[a[i]] = 1;
belong[A - a[i]] = 1;
ss = 1;
}
}
}
if(fail) break;
if(ss == 0) break;
}
}

if(fail == 0) {
for(int i = 1; i <= n; i ++) {
if(belong[a[i]] == 1 && belong[A - a[i]] != 1) fail = 1;
if(belong[a[i]] == 2 && belong[B - a[i]] != 2) fail = 1;
}
}

if(fail) {
printf("NO\n");
} else {
printf("YES\n");
for(int i = 1; i <= n; i ++) {
printf("%d", belong[a[i]] - 1);
if(i < n) printf(" ");
else printf("\n");
}
}

return 0;
}


E - 情人节的电灯泡

单点更新,求子矩阵和,二维树状数组即可。

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

const int maxn = 1010;
int n, m;

int C[maxn][maxn];
int a[maxn][maxn];

int lowbit(int x) {
return x & (-x);
}

void add(int x, int y, int c){
for(int i = x; i <= n; i += lowbit(i)){
for(int j = y; j <= n; j += lowbit(j)){
C[i][j] += c;
}
}
}

int sum(int x,int y){
int ret = 0;
for(int i = x; i > 0; i -= lowbit(i)){
for(int j = y;j > 0;j -= lowbit(j)){
ret += C[i][j];
}
}
return ret;
}

int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j ++) {
scanf("%d", &a[i][j]);
add(i, j, a[i][j]);
}
}
while(m --) {
int op;
scanf("%d", &op);
if(op == 1) {
int x, y;
scanf("%d%d", &x, &y);
if(a[x][y] == 1) {
add(x, y, -1);
} else {
add(x, y, 1);
}
a[x][y] = (a[x][y] ^ 1);
} else {
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", sum(x2, y2) - sum(x1 - 1, y2) - sum(x2, y1 - 1) + sum(x1-1, y1-1));
}
}
return 0;
}


F - The Biggest Water Problem

模拟一下就可以了。

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

long long n;

long long work(long long x) {
long long res = 0;
while(x) {
res += x % 10;
x = x / 10;
}
return res;
}

int main() {
scanf("%d", &n);
while(1) {
if(n <= 9) {
printf("%lld\n", n);
break;
}
n = work(n);
}
return 0;
}


G - 送分啦-QAQ

该题和HDU 2516一样

H - Tree Recovery

区间加,区间求和,线段树就可以了。

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

const int maxn = 1e5 + 10;

int n, Q;
long long sum[4 * maxn];
long long f[4 * maxn];

void pushDown(int l, int r, int rt) {
if(f[rt] == 0) return;
int mid = (l + r) / 2;
int len_left = (mid - l + 1);
int len_right = (r - mid);
f[2 * rt] += f[rt];
f[2 * rt + 1] += f[rt];
sum[2 * rt] += f[rt] * len_left;
sum[2 * rt + 1] += f[rt] * len_right;
f[rt] = 0;
}

void pushUp(int rt) {
sum[rt] =sum[2 * rt] + sum[2 * rt + 1];
}

void build(int l, int r, int rt) {
if(l == r) {
scanf("%lld", &sum[rt]);
return;
}
int mid = (l + r) / 2;
build(l, mid, 2 * rt);
build(mid + 1, r, 2 * rt + 1);
pushUp(rt);
}

void update(int L, int R, long long val, int l, int r, int rt) {
if(L <= l && r <= R) {
sum[rt] += val * (r - l + 1);
f[rt] += val;
return;
}
pushDown(l, r, rt);
int mid = (l + r) / 2;
if(L <= mid) update(L, R, val, l, mid, 2 * rt);
if(R > mid) update(L, R, val, mid + 1, r, 2 * rt + 1);
pushUp(rt);
}

long long query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return sum[rt];
}
pushDown(l, r, rt);
int mid = (l + r) / 2;
long long left = 0;
long long right = 0;
if(L <= mid) left = query(L, R, l, mid, 2 * rt);
if(R > mid) right = query(L, R, mid + 1, r, 2 * rt + 1);
pushUp(rt);
return left + right;
}

int main() {
scanf("%d%d", &n, &Q);
build(1, n, 1);
while(Q --) {
char op[10];
scanf("%s", op);
if(op[0] == 'Q') {
int L, R;
scanf("%d%d", &L, &R);
printf("%lld\n", query(L, R, 1, n, 1));
} else {
int L; int R;
long long val;
scanf("%d%d%lld", &L, &R, &val);
update(L, R, val, 1, n, 1);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐