题解只包含部分题,水题除外。
C. 不重复的数
题意:
有n个数的序列,找出其中所有不重复的数字。
输入:第一行输入一个数字n,第二行输入n个数,每个数的值是a。
输出:从小到大输出所有不重复的数字。
数据范围:1 <= n <=100000 ; 0 <= a <=1e9
思路:
先排序,如果后一个数y如果与前一个数x相同,则将x和y的下标同时进行标记。
注:不可以使用数a为下标,int数组开不到1e9,因为脑残,当时wa了两发。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, p[N];//数组p[]存数
bool st[N];//标记数组
int main()
{
cin >> n;
for(int i=0; i<n; i++) cin >> p[i];
sort(p, p+n);//排序
//对重复出现的数进行标记,下标从1开始
for(int i=1; i<n; i++) {
if(p[i] == p[i-1]) {
st[i] = st[i-1] = true;
}
}
//输出
for(int i=0; i<n; i++)
if(!st[i]) cout << p[i] << " ";
return 0;
}
E.被选数困扰的猪猪
题意:
有n个数,从中任意选取k个数组合得到和sum,求得sum为素数的组合数。
输入:第一行两个空格隔开的整数 n,k(1 <= n <= 20,k < n)。第二行 n 个整数,分别为x1~xn(1 <= x <= 1e6)。
输出:输出一个整数,表示种类数。
思路:
简单搜索,任选取k个数,求其和,判断是否为素数。
代码:
#include <iostream>
#include <cmath>
using namespace std;
int p[21];
int n, k;
int ans, sum;//ans代表和为素数的种类数, sum代表每k个数的和
bool is_prime(int x)
{//判断x是否为素数
for(int i=2; i<=sqrt(x); i++)
if(x % i == 0) return false;
return true;
}
void dfs(int res, int ks)//组合第res个数,选数从ks开始
{
if(res == k) {//k个数的和,判断是否为素数
if(is_prime(sum)) ans++;
return ;
}
for(int i=ks; i<n; i++) {
sum += p[i];
dfs(res+1, i+1);
sum -= p[i];//回溯
}
return ;
}
int main()
{
cin >> n >> k;
for(int i=0; i<n; i++) cin >> p[i];
dfs(0, 0);//
cout << ans << endl;
return 0;
}
F. 石头
题意:
思路:
只有两种情况输出-1,一是n=3并且p[1]为奇数,二是p[1]~p[n-1]都为1。
找出所有-1情况后,根据观察:
(1)两个偶数,移动次数为:(偶数1 + 偶数2) / 2;
(2)两个奇数,移动次数为:(奇数1 + 奇数2) / 2;
(3)三个奇数,移动次数为:(奇数1 + 奇数2 + 奇数3) / 2 + 2;
(4)一个奇数和一个偶数,移动次数为:(奇数+偶数)/ 2 + 1;
得到规律:ans = sum(p[1] ~ p[n-1) / 2 + (count(奇数) + 1) / 2;
代码:
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int t, n;
int p[N];
int main()
{
cin >> t;
while(t--) {
cin >> n;
int s1 = 0;//p[1] ~ p[n-2]中1的个数
int js = 0;//p[1] ~ p[n-2]中除去1外奇数的个数
ll ans = 0;//p[1] ~ p[n-2]所有数的和,ai<=1e9,会爆int
//求和和统计出现次数只针对中间的数,不包括头和尾,故分开输入
cin >> p[0];
for(int i=1; i<n-1; i++) {
cin >> p[i];
ans += p[i];
if(p[i] == 1) s1++;
else if(p[i] % 2 == 1) js++;
}
cin >> p[n-1];
//只有两种情况输出-1,一是n=3并且p[1]为奇数,二是p[1]~p[n-1]都为1
if(s1 == n-2 || (js == 1 && n == 3))
cout << -1 << endl;
//通过观察得到规律:每两个奇数互相“帮助”需要多移动一次,单个奇数得到“帮助”也需多移动一次
else
cout << ans / 2 + (js + s1 + 1) / 2 << endl;
}
return 0;
}
G.A<->BB
题意:
给一个只包含字母A、B或C的字符串s,可以进行以下操作:
操作1:把“A”换替换成“BB”
操作2:把“BB”换替换成“A”
可进行多次操作,使得字符串s长度最短,输出。
思路:
先遍历字符串s,把所有“A”替换成“BB”,再遍历一遍,把所有“BB”都换成“A”,即可得到最短字符串。
代码:
#include <iostream>
#include <string>
using namespace std;
int t;
string s1;//输入的字符串
string s2;//将A全部转化为BB后的字符串
int main()
{
cin >> t;
while(t--) {
cin >> s1;
s2 = "";//置空
for(int i=0; i<s1.size(); i++) {
if(s1[i] == 'A')//先把出现的A全部转化为BB
s2 += "BB";
else
s2 += s1[i];
}
for(int i=0; i<s2.size(); i++) {
//遇见BB时输出A,i跳过下一下标
if(s2[i] == 'B' && s2[i+1] == 'B') {
cout << "A";
i++;
}
else
cout << s2[i];
}
cout << endl;
}
return 0;
}
H.求答案
题意:
思路:
公式可转化为:
为使得f(i, j)最大,则须使得ai取最大值,且aj取较小值,则 i 取下标n-1;
对数组进行从小到大排序后,故f(i, j)的最大值一般为:
但是,因为输入的是实数,存在0 < aj < 1,此时aj虽然在数组中是最小,但aj*aj不一定最小。
因此,只需特判出这种情况,便可AC。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 1e5 + 10;
int t, n;
double p[N];//题目说的输入为实数
double get_ans(int x, int y)
{//计算结果
return sqrt(1.0 / (p[x]*p[x]) - 1.0 / (p[y]*p[y]));
}
int main()
{
cin >> t;
while(t--) {
cin >> n;
bool f = false;//判断是否有大于0且小于1的小数出现
for(int i=0; i<n; i++) {
cin >> p[i];
if(p[i] < 1) f = true;
}
sort(p, p+n);
double ans = get_ans(0, n-1);
if(f) {
for(int i=1; i<n-1; i++)
ans = max(ans, get_ans(i, n-1));
}
printf("%.6lf\n", ans);
}
}