CF EDU6
- [A. Professor GukiZ's Robot](http://codeforces.com/contest/620/problem/A)
- [B. Grandfather Dovlet’s calculator](http://codeforces.com/contest/620/problem/B)
- [C. Pearls in a Row](http://codeforces.com/contest/620/problem/C)
- [D. Professor GukiZ and Two Arrays](http://codeforces.com/contest/620/problem/D)
- [F. Xors on Segments](http://codeforces.com/contest/620/problem/F)
A. Professor GukiZ’s Robot
思路
算出横着能走多少步, 竖着能走多少步。首先走到那个点肯定首先都要把这些步全部走完, 那么, 机器人每次可以同时走x, y各一步, 那么我们可以得出, 走完x, y后再走剩下的那些只向单方向走的步数, 总步数为 m a x ( x , y ) max(x, y) max(x,y)
代码
#include<bits/stdc++.h>
using namespace std;
int sx, sy;
int ex, ey;
int dx, dy;
int main()
{
cin >> sx >> sy >> ex >> ey;
dx = abs(sx - ex);
dy = abs(sy - ey);
//cout << dx << " " << dy << endl;
int maxn = max(dx, dy);
cout << maxn << endl;
return 0;
}
B. Grandfather Dovlet’s calculator
思路
首先求出每个数字又多少发光的杠, 然后从a遍历到b, 对于每个数x, 把他每一位拆出来并加即可。
代码
#include<bits/stdc++.h>
using namespace std;
long long num[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int a, b;
long long cal(int x)
{
long long res = 0;
while(x)
{
int now = x % 10;
x /= 10;
res += num[now];
}
return res;
}
int main()
{
cin >> a >> b;
long long ans = 0;
for(int i = a; i <= b; i++)
{
ans += cal(i);
}
cout << ans << endl;
return 0;
}
C. Pearls in a Row
思路
贪心, 遇到两个一样的就分, 并标记。
如果最后一个不重复, 那把最后这些剩余的归到上一段中。
如果标记为0则输出-1
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[300010];
int k;
set<int> s;
int lp[300010];
int rp[300010];
bool flag = false;
int main()
{
cin >> n;
int l = 1;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
if(s.count(a[i]))
{
flag = true;
k++;
lp[k] = l;
rp[k] = i;
l = i+1;
s.clear();
continue;
}
s.insert(a[i]);
}
if(!flag)
{
printf("-1\n");
return 0;
}
rp[k] = n;
cout << k << endl;
for(int i = 1; i <= k; i++)
{
cout << lp[i] << " " << rp[i] << endl;
}
return 0;
}
D. Professor GukiZ and Two Arrays
这题wa没有A。
思路
我们可以把情况分为三种。
不用交换
直接算总和, 减掉即可
交换1个
O ( n 2 ) O(n^2) O(n2)枚举两数列交换的数;
交换两个
也是枚举两数列交换的数, 只不过其交换的数需要预处理。并排序
记录交换位置
WA代码
#include<bits/stdc++.h>
using namespace std;
int n, m;
int a[2010];
int b[2010];
long long ans1, ans2, ans3;
long long sum1 = 0, sum2 = 0;
void cal1()
{
ans1 = abs(sum2 - sum1);
return;
}
int sa, sb;
void cal2()
{
ans2 = 1e18;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
long long suma = sum1;
long long sumb = sum2;
suma -= a[i];
sumb -= b[j];
suma += b[j];
sumb += a[i];
if(abs(suma - sumb) < ans2)
{
ans2 = abs(suma - sumb);
sa = i;
sb = j;
}
}
}
}
map<long long, pair<int, int> > mpa;
map<long long, pair<int, int> > mpb;
long long paira[2000010];
long long pairb[2000010];
int sa1, sa2, sb1, sb2;
void cal3()
{
ans3 = 1e18;
int cnta = 0, cntb = 0;
for(int i = 1; i <= n; i++)
{
for(int j = i + 1; j <= n; j++)
{
long long now = a[i] + a[j];
mpa[now] = make_pair(i, j);
paira[++cnta] = now;
}
}
for(int i = 1; i <= m; i++)
{
for(int j = i + 1; j <= m; j++)
{
long long now = b[i] + b[j];
mpb[now] = make_pair(i, j);
pairb[++cntb] = now;
}
}
for(int i = 1; i <= cnta; i++)
{
for(int j = 1; j <= cntb; j++)
{
long long suma = sum1;
long long sumb = sum2;
suma = suma - paira[i] + pairb[j];
sumb = sumb - pairb[j] + paira[i];
if(abs(suma - sumb) < ans3)
{
ans3 = abs(suma - sumb);
sa1 = mpa[paira[i]].first;
sa2 = mpa[paira[i]].second;
sb1 = mpb[pairb[i]].first;
sb2 = mpb[pairb[i]].second;
}
}
}
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
cin >> m;
for(int j = 1; j <= m; j++)
{
cin >> b[j];
}
for(int i = 1; i <= n; i++)
{
sum1 += a[i];
}
for(int j = 1; j <= m; j++)
{
sum2 += b[j];
}
cal1();
cal2();
cal3();
if(ans1 <= ans2 && ans1 <= ans3)
{
cout << ans1 << endl;
cout << 0 << endl;
}
else if(ans2 <= ans1 && ans2 <= ans3)
{
cout << ans2 << endl;
cout << 1 << endl;
cout << sa << " " << sb << endl;
}
else
{
cout << ans3 << endl;
cout << 2 << endl;
cout << sa1 << " " << sb1 << endl;
cout << sa2 << " " << sb2 << endl;
}
return 0;
}
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <vector>
namespace OI
{
#define pk putchar(' ')
#define ph puts("")
#define fi first
#define se second
template<class T>
T Fabs(T x)
{
return x < 0 ? -x : x;
}
template<class T>
void rd(T &x)
{
x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())) if (c == '-') f = -1;
do
{
x = (x << 3) + (x << 1) + (c ^ 48);
} while (isdigit(c = getchar()));
x *= f;
}
template<class T>
void pt(T x)
{
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
pt(x / 10);
putchar(x % 10 ^ 48);
}
}
using namespace OI;
using namespace std;
typedef long long ll;
const int N = 2005;
int n, m, a[N], b[N], kind;
ll sa, sb;
vector<pair<int, pair<int, int> > > suma, sumb;
pair<int, int> ans[2];
int main()
{
rd(n);
for (int i = 1; i <= n; i++)
rd(a[i]), sa += a[i];
rd(m);
for (int i = 1; i <= m; i++)
rd(b[i]), sb += b[i];
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
suma.push_back({a[i] + a[j], {i, j}});
for (int i = 1; i < m; i++)
for (int j = i + 1; j <= m; j++)
sumb.push_back({b[i] + b[j], {i, j}});
sort(suma.begin(), suma.end());
sort(sumb.begin(), sumb.end());
ll minx = Fabs(sa - sb);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
ll tmp = Fabs(sa - sb + 2ll * b[j] - 2ll * a[i]);
if (tmp < minx)
{
minx = tmp;
kind = 1;
ans[0] = {i, j};
}
}
for (int i = 0, j = 0; i < (int)suma.size() && j < (int)sumb.size();)
{
ll tmp = (sa - sb + 2ll * sumb[j].fi - 2ll * suma[i].fi);
if (Fabs(tmp) < minx)
{
minx = Fabs(tmp);
kind = 2;
ans[0] = {suma[i].se.fi, sumb[j].se.fi};
ans[1] = {suma[i].se.se, sumb[j].se.se};
}
if (tmp > 0)
i++;
else
j++;
}
pt(minx), ph, pt(kind), ph;
for (int i = 0; i < kind; i++)
pt(ans[i].fi), pk, pt(ans[i].se), ph;
return 0;
}
F. Xors on Segments
思路
前缀异或和;
区间异或和等于前缀异或和两端点异或:
s
u
m
l
−
1
⊕
s
u
m
r
=
区
间
异
或
和
[
l
,
r
]
sum_{l-1} \oplus sum{r} = 区间异或和[l,r]
suml−1⊕sumr=区间异或和[l,r]
证明:
s
u
m
r
=
s
u
m
l
−
1
⊕
[
l
,
r
]
sum_r = sum_{l-1} \oplus [l,r]
sumr=suml−1⊕[l,r]
则
s
u
m
l
−
1
⊕
s
u
m
r
=
s
u
m
l
−
1
⊕
s
u
m
l
−
1
⊕
[
l
,
r
]
=
[
l
,
r
]
sum_{l-1} \oplus sum_r = sum_{l-1} \oplus sum_{l-1} \oplus[l,r] = [l,r]
suml−1⊕sumr=suml−1⊕suml−1⊕[l,r]=[l,r]
所以得证;
我们可以枚举每一个左端点, 做n次DP。
每次DP固定了左端点i, 设f[j]表示以i为左端点, 右端点为j的最大异或和。
这样的话,对于每个询问, 只要它包含这个左端点, 也就是与这个左端点有交集,那么我们就更新他的答案, f[r]是以i为左端点在当前[l,r]区间询问的异或最大值
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int m;
int a[50010];
int sum[1000010];
int l[5010];
int r[5010];
int f[50010];
int ans[5010];
int main()
{
for(int i = 1; i <= 1000010; i++)
{
sum[i] = sum[i-1] ^ i;
}
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
for(int i = 1; i <= m; i++)
{
cin >> l[i] >> r[i];
}
for(int i = 1; i <= n; i++)
{
f[i] = a[i];
for(int j = i + 1; j <= n; j++)
{
f[j] = max(f[j-1], sum[min(a[i], a[j])-1] ^ sum[max(a[i], a[j])]);
}
for(int j = 1; j <= m; j++)
{
if(i >= l[j] && i <= r[j])
{
ans[j] = max(ans[j], f[r[j]]);
}
}
}
for(int i = 1; i <= m; i++)
{
cout << ans[i] << endl;
}
return 0;
}