Problem A
给定一个数,求两个合数,差为这个数。构造方法有很多。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int judge(int n) {
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++) if (n % i == 0)
return 1;
return 0;
}
int main()
{
int n;
scanf("%d", &n);
if (n & 1)
printf("%d %d\n", 9 + n, 9);
else
printf("%d %d\n", 4 + n, 4);
return 0;
}
Problem B
给定两个长度均为n的数组,和
。以及一个正整数m。
要求找到一个最小的x,使得经过如下运算后,a能经过重新排列等于b。
其中,n的范围是[1,2000],m的范围是[1,10^9]。
分析:无需关心如何排列,只要将a变换之后,与b相等的每个值数量也相等即可。
首先想到可以将两个数组重新组合为<值,数量>的形式,之后按值排序。得到代码中的va和vb。
枚举va的第一个元素和vb中的哪个元素对齐,对齐之后x很容易得到,并且相当于将vb当做一个圈,依次和va的每个元素比较是否相等即可。
这里出错在于判断枚举位置是否合法时,只判断了每个单元数量是否相等,而没有变换后值是否相等。
注意:条件一定要仔细分析,写全。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
map<int, int> a, b;
vector<pair<int, int> > va, vb;
vector<pair<int, int> > vc;
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
int t;
scanf("%d", &t);
if (a.count(t)) a[t]++;
else a.insert(pair<int, int>(t, 1));
}
for (int i = 0; i < n; i++) {
int t;
scanf("%d", &t);
if (b.count(t)) b[t]++;
else b.insert(pair<int, int>(t, 1));
}
for (map<int, int>::iterator ite = a.begin(); ite != a.end(); ite++) va.push_back(pair<int, int>(ite->first, ite->second));
for (map<int, int>::iterator ite = b.begin(); ite != b.end(); ite++) vb.push_back(pair<int, int>(ite->first, ite->second));
int res = 0x7fffffff;
for (int i = 0; i < vb.size(); i++) {
bool yes = true;
int fac = (vb[i].first - va[0].first + m) % m;
for (int j = 0, k = i; j < va.size(); j++, k = (k + 1) % vb.size()) if(va[j].second!=vb[k].second|| (va[j].first+fac)%m != vb[k].first){
yes = false;
break;
}
if (yes) {
res = min(res, fac);
}
}
printf("%d\n", res);
return 0;
}
Problem C
给定一个n位整数,然后给定一个k,并认为如果每一位都满足bi=bi+k,就认为该数字是美的。求大于等于给定数字的最小美数。
n的范围为[2,200000],k的范围为[1,n)。
分析:一开始想到的是,先将数字按bi=bi+k处理,得到的新数字如果已经大于等于原数字,则直接输出即可,并且已经明确数字位数不会发生变化。
如果处理后数字小于原数字,则需要对某些位进行变化。可知我们为了保证数字最小,应该在最低位增加,即如果大于的位置在k位之后,则直接令第k位加1并修改其余位即可,如果在k位之前,则直接令这一位加1并修改其余位即可。
出错的地方在于,一方面错误认为如果小的位数在1-k之间,那么加1并不一定能保证大于原数。可知,前K位和原数相等,若某一位加1,一定大于原数
另一个错误的原因在于,没有处理第k位为9的情况。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
char d[200010];
char r[200010];
int judge(int size) {
int pos = 0;
while (pos < size && d[pos] == r[pos]) pos++;
if (pos == size) return 0;
if (d[pos] > r[pos]) return -1 * (pos + 1);
return 1;
}
int main()
{
int n, k;
scanf("%d%d", &n, &k); getchar();
scanf("%s", d);
int size = strlen(d);
r[size] = 0;
for (int i = 0; i < size; i++) r[i] = d[i];
for (int i = k; i < size; i++) r[i] = r[i - k];
int pos = judge(size);
if (pos < 0) {
pos = -1 * pos - 1;
if (pos > k - 1) pos = k - 1;
while (r[pos] == '9') pos--;
r[pos++]++;
while (pos < k) r[pos++] = '0';
for (int i = k; i < size; i++) r[i] = r[i - k];
}
printf("%d\n", size);
printf("%s\n", r);
return 0;
}
Problem D
给定一个长度为n的非递增序列,表示如下一幅图:
相邻两个可以构成一个单位,求做多可以构成多少个单位。
n的范围为[1,300000]。序列每个元素的范围为[1,300000]
分析:这一题思路很巧妙,用黑白两种颜色给整个图填色,相邻方格不同色即可。对于填好色的图,可知一个单元必定由一黑一白构成,如果黑格数量少,则每个黑格必定可以和一个白格对应,反之亦然,所以,最终变为求白块和黑块的数量,并计算最小值即可。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
long long a = 0, b = 0;
for (int i = 0; i < n; i++) {
int t;
scanf("%d", &t);
if (t & 1) {
a += t >> 1;
b += t >> 1;
if (i & 1) b++;
else a++;
}
else {
a += t >> 1;
b += t >> 1;
}
}
printf("%lld\n", min(a,b));
return 0;
}