小Q定义了一种数列称为翻转数列:
给定整数n和m, 满足n能被2m整除。对于一串连续递增整数数列1, 2, 3, 4…, 每隔m个符号翻转一次, 最初符号为’-’;。
例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
小Q现在希望你能帮他算算前n项和为多少。
输入描述:
输入包括两个整数n和m(2 <= n <= 109, 1 <= m), 并且满足n能被2m整除。
输出描述:
输出一个整数, 表示前n项和。
输入例子1:
8 2
输出例子1:
8
#include
using namespace std;
// 暴力法 case通过率为80.00%,超时
long long fun(int n, int m) {
long long res = 0;
int k = 0, flag = -1;
for (int i = 0; i < n/m; i++){
for (int j = 0; j < m; j++){
k = flag * (abs(k) + 1);
res += k;
}
flag *= -1;
}
return res;
}
// 找规律:第一个加号值加上第一个减号值,差值刚好是m,共有n/2对
// -1, -2, +3, +4, -5, -6, +7, +8
long long fun2(int n, int m) {
return n/2*m;
}
int main() {
int n, m;
cin >> n >> m;
cout << fun2(n,m) << endl;
return 0;
}
牛牛和羊羊正在玩一个纸牌游戏。这个游戏一共有n张纸牌, 第i张纸牌上写着数字ai。
牛牛和羊羊轮流抽牌, 牛牛先抽, 每次抽牌他们可以从纸牌堆中任意选择一张抽出, 直到纸牌被抽完。
他们的得分等于他们抽到的纸牌数字总和。
现在假设牛牛和羊羊都采用最优策略, 请你计算出游戏结束后牛牛得分减去羊羊得分等于多少。
输入描述:
输入包括两行。
第一行包括一个正整数n(1 <= n <= 105),表示纸牌的数量。
第二行包括n个正整数ai(1 <= ai <= 109),表示每张纸牌上的数字。
输出描述:
输出一个整数, 表示游戏结束后牛牛得分减去羊羊得分等于多少。
输入例子1:
3
2 7 4
输出例子1:
5
#include
#include
#include
using namespace std;
int main(){
int n;
cin >> n;
priority_queue<int, vector<int>,less<int>> card;
int t;
for (int i = 0; i < n; i++){
cin >> t;
card.push(t);
}
int res = 0;
int flag = 1;
while (!card.empty()){
int c = card.top();
res += flag*c;
flag *= -1;
card.pop();
}
cout << res << endl;
return 0;
}
小Q的父母要出差N天,走之前给小Q留下了M块巧克力。小Q决定每天吃的巧克力数量不少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有巧克力吃,请问他第一天最多能吃多少块巧克力
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,表示父母出差的天数N(N<=50000)和巧克力的数量M(N<=M<=100000)。
输出描述:
输出一个数表示小Q第一天最多能吃多少块巧克力。
输入例子1:
3 7
输出例子1:
4
#include
#include
using namespace std;
int fun(int n, int m){
int start = ceil(m / 2.0);
for (int i = start; i >= 1; i--){
int t = 0;
int ti = i;
for (int j = 0; j < n; j++){
t += ti;
if (ti != 1)
ti = ceil(ti / 2.0);
}
if (t <= m)
return i;
}
return 0;
}
int main(){
int n, m;
cin >> n >> m;
if (n == 1)
cout << m << endl;
else
cout << fun(n, m) << endl;
return 0;
}
小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000)。
接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数量Y(Y<=100)。保证A不等于B。
输出描述:
输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。
输入例子1:
5
2 3 3 3
输出例子1:
9
#include
#include
using namespace std;
// n选k组合数C(n,k) = C(n-1,k) + C(n-1,k-1)
void CreatSelect(vector<vector<long long>> &arr){
arr[0][0] = 1;
for (int i = 1; i <= 100; i++){
arr[i][0] = 1;
for (int j = 1; j <= 100; j++){
arr[i][j] = (arr[i - 1][j] + arr[i - 1][j - 1] )% 1000000007;
}
}
}
long long fun(int k, int a, int x, int b, int y, vector<vector<long long>> arr){
long long res = 0;
for (int i = 0; i <= k / a && i <= x; i++){
if ((k - a*i) % b == 0 && (k - a*i) / b <= y){
// x里选i个a,y里选(k - a*i) / b个b
res = (res + arr[x][i] * arr[y][(k - a*i) / b] % 1000000007) % 1000000007;
}
}
return res;
}
int main(){
int k;
cin >> k;
int a, b, x, y;
cin >> a >> x >> b >> y;
vector<vector<long long>> arr(101, vector<long long>(101));
CreatSelect(arr);
cout << fun(k, a, x, b, y, arr) << endl;
return 0;
}
小Q的公司最近接到m个任务, 第i个任务需要xi的时间去完成, 难度等级为yi。
小Q拥有n台机器, 每台机器最长工作时间zi, 机器等级wi。
对于一个任务,它只能交由一台机器来完成, 如果安排给它的机器的最长工作时间小于任务需要的时间, 则不能完成,如果完成这个任务将获得200 * xi + 3 * yi收益。
对于一台机器,它一天只能完成一个任务, 如果它的机器等级小于安排给它的任务难度等级, 则不能完成。
小Q想在今天尽可能的去完成任务, 即完成的任务数量最大。如果有多种安排方案,小Q还想找到收益最大的那个方案。小Q需要你来帮助他计算一下。
输入描述:
输入包括N + M + 1行,
输入的第一行为两个正整数n和m(1 <= n, m <= 100000), 表示机器的数量和任务的数量。
接下来n行,每行两个整数zi和wi(0 < zi < 1000, 0 <= wi <= 100), 表示每台机器的最大工作时间和机器等级。
接下来的m行,每行两个整数xi和yi(0 < xi < 1000, 0 <= yi<= 100), 表示每个任务需要的完成时间和任务的难度等级。
输出描述:
输出两个整数, 分别表示最大能完成的任务数量和获取的收益。
输入例子1:
1 2
100 3
100 2
100 1
输出例子1:
1 20006
#include
#include
#include
#include
using namespace std;
struct Node {
int time, grade;
};
bool Cmp(const Node &a, const Node &b) {
if (a.time == b.time)
return a.grade > b.grade;
return a.time > b.time;
}
// case通过率为90.00%,超时
int main() {
int n, m; //机器的数量和任务的数量 1 <= n, m <= 100000
cin >> n >> m;
vector<Node> machine(n);
vector<Node> task(m);
for (int i = 0; i < n; i++){
cin >> machine[i].time >> machine[i].grade;
}
for (int i = 0; i < m; i++){
cin >> task[i].time >> task[i].grade;
}
sort(machine.begin(), machine.end(), Cmp);
sort(task.begin(), task.end(), Cmp);
int res = 0, value = 0;
bool* flag = new bool[n];
memset(flag, true, n);
for (int i = 0; i < m; i++){
int min_grade = 101;
int min_j;
for (int j = 0; j < n; j++){
if (flag[j]){
if (task[i].time <= machine[j].time){
if (task[i].grade <= machine[j].grade && machine[j].grade < min_grade){
min_grade = machine[j].grade;
min_j = j;
}
}
else{
break;
}
}
}
if (min_grade != 101){
res++;
value += 200 * task[i].time + 3 * task[i].grade;
flag[min_j] = false;
}
}
delete[] flag;
cout << res << " " << value << endl;
return 0;
}
画家小Q又开始他的艺术创作。小Q拿出了一块有NxM像素格的画板, 画板初始状态是空白的,用’X’表示。
小Q有他独特的绘画技巧,每次小Q会选择一条斜线, 如果斜线的方向形如’/’,即斜率为1,小Q会选择这条斜线中的一段格子,都涂画为蓝色,用’B’表示;如果对角线的方向形如’’,即斜率为-1,小Q会选择这条斜线中的一段格子,都涂画为黄色,用’Y’表示。
如果一个格子既被蓝色涂画过又被黄色涂画过,那么这个格子就会变成绿色,用’G’表示。
小Q已经有想画出的作品的样子, 请你帮他计算一下他最少需要多少次操作完成这幅画。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数N和M(1 <= N, M <= 50), 表示画板的长宽。
接下来的N行包含N个长度为M的字符串, 其中包含字符’B’,‘Y’,‘G’,‘X’,分别表示蓝色,黄色,绿色,空白。整个表示小Q要完成的作品。
输出描述:
输出一个正整数, 表示小Q最少需要多少次操作完成绘画。
输入例子1:
4 4
YXXB
XYGX
XBYY
BXXY
输出例子1:
3
例子说明1:
XXXX
XXXX
XXXX
XXXX
->
YXXX
XYXX
XXYX
XXXY
->
YXXB
XYBX
XBYX
BXXY
->
YXXB
XYGX
XBYY
BXXY
#include
#include
#include
using namespace std;
int n, m; //N和M(1 <= N, M <= 50), 表示画板的长宽
vector<vector<char>> arr;
void fun_b(int i, int j){
if (i >= 0 && i < n && j >= 0 && j < m && (arr[i][j] == 'B' || arr[i][j] == 'G')){
if (arr[i][j] == 'B')
arr[i][j] = 'X';
else
arr[i][j] = 'Y';
fun_b(i - 1,j + 1);
fun_b(i + 1, j - 1);
}
return;
}
void fun_y(int i, int j){
if (i >= 0 && i < n && j >= 0 && j < m && (arr[i][j] == 'Y' || arr[i][j] == 'G')){
if (arr[i][j] == 'Y')
arr[i][j] = 'X';
else
arr[i][j] = 'B';
fun_y(i + 1, j + 1);
fun_y(i - 1, j - 1);
}
return;
}
/*
YXXB
XYGX
XBYY
BXXY
*/
int fun() {
int res = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (arr[i][j] == 'B'){
fun_b(i, j);
res++;
}
if (arr[i][j] == 'Y'){
fun_y(i, j);
res++;
}
if (arr[i][j] == 'G'){
fun_b(i, j);
fun_y(i, j);
res += 2;
}
}
}
return res;
}
int main() {
cin >> n >> m;
arr = vector<vector<char>> (n, vector<char>(m));
string str;
for (int i = 0; i < n; i++){
cin >> str;
for (int j = 0; j < m; j++){
arr[i][j] = str[j];
}
}
cout << fun() << endl;
return 0;
}
假定一种编码的编码范围是a ~ y的25个字母,从1位到4位的编码,如果我们把该编码按字典序排序,形成一个数组如下: a, aa, aaa, aaaa, aaab, aaac, … …, b, ba, baa, baaa, baab, baac … …, yyyw, yyyx, yyyy 其中a的Index为0,aa的Index为1,aaa的Index为2,以此类推。 编写一个函数,输入是任意一个编码,输出这个编码对应的Index.
输入描述:
输入一个待编码的字符串,字符串长度小于等于100.
输出描述:
输出这个编码的index
输入例子1:
baca
输出例子1:
16331
#include
#include
#include
using namespace std;
vector<int> loop = { 0, 1, 26, 651, 16276 };
int fun(string str) {
int res = 0, len = str.size();
for (int i = 0; i < len; i++){
res += (str[i] - 'a')*loop[4 -i]+1;
}
return res-1;
}
int main() {
string str;
while (cin >> str){
cout << fun(str) << endl;
}
return 0;
}
游戏里面有很多各式各样的任务,其中有一种任务玩家只能做一次,这类任务一共有1024个,任务ID范围[1,1024]。请用32个unsigned int类型来记录着1024个任务是否已经完成。初始状态都是未完成。 输入两个参数,都是任务ID,需要设置第一个ID的任务为已经完成;并检查第二个ID的任务是否已经完成。 输出一个参数,如果第二个ID的任务已经完成输出1,如果未完成输出0。如果第一或第二个ID不在[1,1024]范围,则输出-1。
输入描述:
输入包括一行,两个整数表示人物ID.
输出描述:
输出是否完成
输入例子1:
1024 1024
输出例子1:
1
#include
using namespace std;
unsigned int flag[32];
// unsigned int为32位,32个unsigned int为32*32=1024
int fun(int n, int m) {
// Index(N) = N / 32 = N >> 5;
// Position(N) = N % 32 = N & 31; (对于2的幂的数才能)
int index, position;
index = (n - 1) >> 5;
position = (n-1) & 31;
flag[index] |= 1 << position;
if (m >= 1 && m <= 1024){
index = (m - 1) >> 5;
position = (m - 1) & 31;
return (flag[index]&(1<<position))!=0;
}
return -1;
}
int main() {
int n,m;
cin >> n >> m;
cout << fun(n, m) << endl;
return 0;
}
给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。输入值小于1000。
如,输入为10, 程序应该输出结果为2。(共有两对质数的和为10,分别为(5,5),(3,7))
输入描述:
输入包括一个整数n,(3 ≤ n < 1000)
输出描述:
输出对数
输入例子1:
10
输出例子1:
2
#include
using namespace std;
// 质数:只能被1和本身整除,最小质数为2
bool is_zhishu(int x) {
for (int i = 2; i*i <= x; i++){
if (x%i == 0)
return false;
}
return true;
}
int fun(int n) {
int res = 0;
for (int i = 2; i <= n / 2; i++){
if (is_zhishu(i) && is_zhishu(n - i))
res++;
}
return res;
}
int main() {
int n;
cin >> n;
cout << fun(n) << endl;
return 0;
}
geohash编码:geohash常用于将二维的经纬度转换为字符串,分为两步:第一步是经纬度的二进制编码,第二步是base32转码。
此题考察纬度的二进制编码:算法对纬度[-90, 90]通过二分法进行无限逼近(取决于所需精度,本题精度为6)。注意,本题进行二分法逼近过程中只采用向下取整来进行二分,针对二分中间值属于右区间。算法举例如下: 针对纬度为80进行二进制编码过程:
输入描述:
输入包括一个整数n,(-90 ≤ n ≤ 90)
输出描述:
输出二进制编码
输入例子1:
80
输出例子1:
111100
#include
#include
#include
using namespace std;
// -66
string fun(int n) {
string res;
int k = 0;
int l = -90, r = 90;
while (k != 6){
int mid = floor((l + r) / 2.0);
if (mid <= n){
res.push_back('1');
l = mid;
}
else{
res.push_back('0');
r = mid;
}
k++;
}
return res;
}
string fun2(int n) {
string res;
int k = 0;
int l = -90, r = 90;
while (k != 6){
int mid = l + r > 0 ? floor((l + r) / 2.0) : -floor(-(l + r) / 2.0);
if (mid <= n){
res.push_back('1');
l = mid;
}
else{
res.push_back('0');
r = mid;
}
k++;
}
return res;
}
int main() {
int n; // (-90 ≤ n ≤ 90)
cin >> n;
cout << fun2(n) << endl;
return 0;
}
注:题中向下取整存在歧义
给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出一个整数,代表最少需要删除的字符个数。
输入例子1:
abcda
google
输出例子1:
2
2
#include
#include
#include
#include
using namespace std;
// 求原字符串和其反串的最大公共子序列的长度
int fun(string s1, string s2) {
if (s1.size() == 1) return 1;
int len = s1.size();
vector<vector<int>> arr(len + 1, vector<int>(len + 1));
for (int i = 0; i <= len; i++){
for (int j = 0; j <= len; j++){
if (i == 0 || j == 0){
arr[i][j] =0;
}
else if (s1[i-1] == s2[j-1]){
arr[i][j] = arr[i - 1][j - 1] + 1;
}
else{
arr[i][j] = max(arr[i][j - 1], arr[i-1][j]);
}
}
}
return arr[len][len];
}
int main() {
string s; // 1 <= s.length <= 1000
while (cin >> s){
string s2 = s;
reverse(s2.begin(), s2.end());
cout << s.size()-fun(s,s2) << endl;
}
return 0;
}
小Q最近遇到了一个难题:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
你能帮帮小Q吗?
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出移位后的字符串。
输入例子1:
AkleBiCeilD
输出例子1:
kleieilABCD
#include
#include
using namespace std;
bool is_upper(char c){
return c >= 'A' && c <= 'Z';
}
string fun(string &s) {
if (s.size() == 1) return s;
for (int i = 0; i < s.size(); i++){
if (is_upper(s[i])){
for (int j = i + 1; j < s.size(); j++){
if (!is_upper(s[j])){
int k = j;
char t = s[j];
while (k>i){
s[k] = s[k - 1];
k--;
}
s[i] = t;
break;
}
}
}
}
return s;
}
int main() {
string s; // 1 <= s.length <= 1000
while (cin >> s){
cout << fun(s) << endl;
}
return 0;
}
小Q今天在上厕所时想到了这个问题:有n个数,两两组成二元组,相差最小的有多少对呢?相差最大呢?
输入描述:
输入包含多组测试数据。
对于每组测试数据:
N - 本组测试数据有n个数
a1,a2…an - 需要计算的数据
保证:
1<=N<=100000,0<=ai<=INT_MAX.
输出描述:
对于每组数据,输出两个数,第一个数表示差最小的对数,第二个数表示差最大的对数。
输入例子1:
6
45 12 45 32 5 6
输出例子1:
1 2
#include
#include
#include
using namespace std;
void fun(int n,vector<int> &vec) {
int min_count = 0, max_count = 0;
if (n > 1){
sort(vec.begin(), vec.end());
if (vec[0] == vec[n - 1]){ // 11111
min_count = n*(n - 1) / 2;
max_count = n*(n - 1) / 2;
}
else{
// min
int min = vec[1] - vec[0];
for (int i = 0; i < n - 1; i++){
if (vec[i + 1] - vec[i] < min){
min = vec[i + 1] - vec[i];
}
}
if (min == 0){ // 11233
int time;
for (int i = 0; i < n; i++){
time = 1;
while (i + 1 < n && vec[i + 1] == vec[i]){
time++;
i++;
}
min_count += time*(time - 1)/2;
}
}
else{ // 12457
for (int i = 0; i < n - 1; i++){
if (vec[i + 1] - vec[i] == min){
min_count++;
}
}
}
// max
int max = vec[n - 1] - vec[0];
int l = 0, r = 0;
for (int i = 0; i < n; i++){
if (vec[i] == vec[0]) l++;
else break;
}
for (int i = n - 1; i >= 0; i--){
if (vec[i] == vec[n-1]) r++;
else break;
}
max_count = l*r;
}
}
cout << min_count << " " << max_count << endl;
}
int main() {
int n;
while (cin >> n){
vector<int> vec(n);
for (int i = 0; i < n; i++){
cin >> vec[i];
}
fun(n, vec);
}
return 0;
}
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同, 则称这种编码为格雷码(Gray Code),请编写一个函数,使用递归的方法生成N位的格雷码。
给定一个整数n,请返回n位的格雷码,顺序为从0开始。
测试样例:
1
返回:[“0”,“1”]
/*n: 0 1 2 3
0 0 00 000
1 10 100
110
11 010
01
011
111
101
001
*/
class GrayCode {
public:
// 题目不严谨case通过率为9.09%
// 用例:2
// 对应输出应该为:["00","01","11","10"]
// 你的输出为:["00","10","11","01"]
vector<string> getGray2(int n) {
if (n == 0) return{ "0" };
vector<string> res{ "0", "1" };
for (int i = 1; i < n; i++){
for (int j = 0; j < res.size(); j++){
res[j].push_back('0');
}
for (int j = res.size()-1; j >=0; j--){
string t = res[j];
t[t.size() - 1] = '1';
res.push_back(t);
}
}
return res;
}
vector<string> getGray(int n) {
if (n == 0) return{ "0" };
vector<string> res{ "0", "1" };
for (int i = 1; i < n; i++){
for (int j = 0; j < res.size(); j++){
res[j]='0' + res[j];
}
for (int j = res.size()-1; j >=0; j--){
string t = res[j];
t[0] = '1';
res.push_back(t);
}
}
return res;
}
};
春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。
给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。
若没有金额超过总数的一半,返回0。
测试样例:
[1,2,3,2,2],5
返回:2
class Gift {
public:
/*
如果重复的次数超过一半的话,一定有相邻的数字相同这种情况的
对数组同时去掉两个不同的数字,到最后剩下的一个数就是该数字
*/
int getValue(vector<int> gifts, int n) {
int res = gifts[0], time = 1;
for(int i=1;i<gifts.size();i++){
if(gifts[i]==res) time++;
else{
time--;
if(time == 0){
res = gifts[i];
}
}
}
time = 0;
for(int i=0;i<gifts.size();i++){
if(gifts[i] == res) time++;
}
return time>gifts.size()/2?res:0;
}
};