XUPT 寒假算法集训第一周

A - 连续数的和

给你一个整数nn,你需要找到两个整数ll和rr,它们的范围是: -10^18 ≤l<r≤10^18 并且使得 l + (l + 1) +... + (r - 1) + r =n.

Input

第一行输入一个单独的整数 t (-10^4≤t≤10^4) — 表示测试用例的组数。

每组测试用例只有一行,每行只有一个整数 n (-10^18≤n≤10^18).

Output

对于每组测试用例,输出两个整数 l 和 r,令 l + (l + 1) + ...+ (r - 1) + r = l+(l+1)+…+(r−1)+r=n,且-10^18 ≤l<r≤10^18.

可以证明答案一定存在,如果有多种不同的答案,只需输出其中任意一种即可。

 Example

Input

7
1
2
3
6
100
25
3000000000000

Output

0 1
-1 2 
1 2 
1 3 
18 22
-2 7
999999999999 1000000000001

 因为不需要确定几组数据相加, 所以正负抵消, 再加上本身就可以了

#include<stdio.h>
int main()
{
	long long int n;
	scanf("%lld", &n);
	long long int a, b, c;

	while (n--)
	{
		scanf("%lld", &a);
		b = -a + 1;
		c = a;
		printf("%lld %lld\n", b,c);
	}
	return 0;
}

 

C - Do Not Be Distracted!

 

Polycarp has 2626 tasks. Each task is designated by a capital letter of the Latin alphabet.

The teacher asked Polycarp to solve tasks in the following way: if Polycarp began to solve some task, then he must solve it to the end, without being distracted by another task. After switching to another task, Polycarp cannot return to the previous task.

Polycarp can only solve one task during the day. Every day he wrote down what task he solved. Now the teacher wants to know if Polycarp followed his advice.

For example, if Polycarp solved tasks in the following order: "DDBBCCCBBEZ", then the teacher will see that on the third day Polycarp began to solve the task 'B', then on the fifth day he got distracted and began to solve the task 'C', on the eighth day Polycarp returned to the task 'B'. Other examples of when the teacher is suspicious: "BAB", "AABBCCDDEEBZZ" and "AAAAZAAAAA".

If Polycarp solved the tasks as follows: "FFGZZZY", then the teacher cannot have any suspicions. Please note that Polycarp is not obligated to solve all tasks. Other examples of when the teacher doesn't have any suspicious: "BA", "AFFFCC" and "YYYYY".

Help Polycarp find out if his teacher might be suspicious.

Input

The first line contains an integer tt (1 \le t \le 10001≤t≤1000). Then tt test cases follow.

The first line of each test case contains one integer nn (1 \le n \le 501≤n≤50) — the number of days during which Polycarp solved tasks.

The second line contains a string of length nn, consisting of uppercase Latin letters, which is the order in which Polycarp solved the tasks.

Output

For each test case output:

  • "YES", if the teacher cannot be suspicious;
  • "NO", otherwise.

You may print every letter in any case you want (so, for example, the strings yEs, yes, Yes and YES are all recognized as positive answer). 

InputcopyOutputcopy
5
3
ABA
11
DDBBCCCBBEZ
7
FFGZZZY
1
Z
2
AB
NO
NO
YES
YES
YES

 

#include<stdio.h>
int main()
{
	int t, n;
	char a[55];
	scanf("%d", &t);
	while (t--)
	{
		int x = 1;
		scanf("%d %s", &n,a);
		for (int i = 0; i < n; i++)
		{
			if (a[i] != a[i - 1])
			{
				for (int j = 0; j < i; j++)
				{
					if (a[i] == a[j])
					{
						x = 0;
						break;
					}
				}
				
			}
		}
		if (x == 1) printf("YES\n");
		else printf("NO\n");
		
	}
	return 0;
}

D - 地毯

 

在 n×n 的格子上有 m 个地毯。

给出这些地毯的信息,问每个点被多少个地毯覆盖。

输入格式

第一行,两个正整数n (1≤n≤1000)、m (1≤m≤105),意义如题所述。

接下来 m 行,每行两个坐标 (x1,y1) 和 (x2​,y2​),代表一块地毯,左上角是 (x1​,y1​),右下角是 (x2​,y2​)。

输出格式

输出 n 行,每行 n 个正整数。

第 i 行第 j 列的正整数表示 (i,j) 这个格子被多少个地毯覆盖。

InputcopyOutputcopy
4 3
1 1 3 3
2 2 4 4
3 1 4 3
1 1 1 0
1 2 2 1
2 3 3 1
1 2 2 1

使用前缀和, 差分 

#include<stdio.h>
int a[1010][1010],i,j,n,m,x1,x2,y1,y2;
int main()
{
	scanf("%d %d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		for(j=x1;j<=x2;j++)
		{
			a[j][y1]++;
			a[j][y2+1]--;
		}
	}   
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			a[i][j]+=a[i][j-1];
		}
	}   
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 E - 纪念品分组

元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。

你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

输入格式

第 1 行包括一个整数 w,为每组纪念品价格之和的上限。

第 2 行为一个整数 n,表示购来的纪念品的总件数。

第 3∼n+2 行每行包含一个正整数\pi​(5≤pi​≤w) ,表示所对应纪念品的价格。

输出格式

包含一个整数,即最少的分组数目。

数据范围

50% 的数据满足:1≤n≤15。

100% 的数据满足: 1≤n≤30000,80≤w≤200。

InputcopyOutputcopy
100
9
90
20
20
30
50
60
70
80
90
6

排序, 始终让最小的与最大的进行组队,  如果可以组队, 左右标记分别移动

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int a[30005], w, n, t = 0, i, l, r;
int main()
{
	scanf("%d", &w);
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	l = 1; r = n;
	sort(a + 1, a + 1 + n);
	while (l <= r)
	{
		if (a[l] + a[r] > w && l != r)
		{
			t++;
			r--;
		}
		else
		{
			t++;
			l++;
			r--;
		}
	}
	printf("%d", t);

	return 0;
}

 G - 学生成绩查找系统

学生成绩查找系统是一个根据姓名查找学生成绩的系统。系统可以录入是学生的姓名和成绩,录完之后可以输入查找条件,即学生的姓名,查找该生的成绩,如果存在该生的信息,则输出该生成绩,否则给出查无此人的提示信息。

输入:题目输入包括录入学生信息和输入查找条件以及输入结束标志。insert语句表示录入学生信息,格式为字符insert+空格+字符串+空格+数字+换行符 ,例如 insert xiaohua 99 ,表示录入姓名为xiaohua的学生,其成绩为99 。 find语句表示查找某学生的信息,格式为字符find+空格+字符串+换行符。例如 find xiaohua。end语句表示输入结束,格式为字符end

输出:对应每一条find语句都应该有一条输出语句。对于find xiaohua这条输入语句,因为已经插入过xiaohua的成绩 需要输出 99+换行符,否则查找不到输出-1+换行符。

InputcopyOutputcopy
insert zhangsan 90
insert lisi 78
insert xiaoming 86
find xiaoming
find Jack
end
86
-1

使用map函数, 内部一一对应 

#include<stdio.h>
#include<iostream>
#include<map>
#include<string.h>
using namespace std;

char a[10] = { "insert" };
char b[10] = { "find" };
char c[10] = { "end" };
char d[30], e[30], f[30];
char name[30];
int grade;
map<string,int>x;

int main()
{
	while (scanf("%s", d) != EOF)
	{
		if (strcmp(a,d) == 0)
		{
			scanf("%s %d", e, &grade);  
			x[e]=grade;  //名字对应成绩

		}
		else if(strcmp(b,d)==0)
		{
			scanf("%s",f);
			if(x[f])  //这个名字的成绩存在
			printf("%d\n",x[f]);
			else
			printf("-1\n");
		}
		else if(strcmp(c,d)==0) //输入end,跳出循环
		break;
	}

	return 0;
}

 

I - 买鸡问题

 (这是我软协二面的题哦, waw学姐问的)

百钱买百鸡问题:公鸡五文钱一只,母鸡三文钱一只,小鸡三只一文钱,用 100 文钱买 100 只鸡,公鸡、母鸡、小鸡各买多少只?

本程序要求解的问题是:给定一个正整数 n,用 n 文钱买 n 只鸡,问公鸡、母鸡、小鸡各买多少只?

输入格式

输入一个正整数 nn。

输出格式

如果有解,依次输出公鸡、母鸡、小鸡的个数(用正整数表示)。

如果无解,输出"No Answer."

数据范围

1≤n≤200。

InputcopyOutputcopy
100
0 25 75
4 18 78
8 11 81
12 4 84
#include<stdio.h>

int main()
{
	int n, i, j, t = 0;;
	scanf("%d", &n);
	for (i = 0; i < n/5; i++) //优化,i不可能取到n
	{
		for (j = 0; j < n/3; j++)
		{
			if (5 * i + 3 * j + (n - i - j) / 3 == n && (n - i - j) % 3 == 0) //保证小鸡个数为整数
			{
				printf("%d %d %d\n", i, j, n - i - j);
				t = 1;
			}
			
		}
	}
	if (t == 0)
		printf("No Answer.");
	return 0;
}

 J - 暖气坏了

蒜头君家的暖气经常出问题,每当暖气坏了,蒜头君就会持续感冒 m 天(从坏的那天算起,两次感冒时间重叠不会累加)。蒜头君去寻求预言家的帮助,预言家告诉他接下来 n 次暖气片坏掉的时间。根据这个时间,蒜头君就能知道他未来获得感冒的总天数。

输入格式

第一行两个整数 n,m,表示暖气片坏掉的次数以及每次感冒的持续天数。

第二行 n 个整数 ai​,表示暖气片坏掉的日期。

数据范围: 1≤n≤10000,1≤m,ai​≤10^9,保证 ai​ 是严格递增的。

输出格式

一个整数,表示蒜头君感冒的总天数。

InputcopyOutputcopy
4 3
1 2 4 8
9

 判断第一次暖气坏与第二次暖气坏的间隔是否小于感冒持续天数

#include<stdio.h>
#include<iostream>
#include<string.h>

using namespace std;

int n, m, t = 0;
int a[10010];

int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    for (int i = 0; i < n-1; i++)
    {
        if (a[i + 1] - a[i] <= m - 1) t += a[i + 1] - a[i];
        else t += m;
    }
    t += m;
    printf("%d", t);

    return 0;
}

K - 母牛的故事

有一头母牛,它每年年中生一头小母牛。每头小母牛从第四个年头开始,每年年中也生一头小母牛。请编程实现在第 n 年的时候(不算第 n 年出生的小母牛),共有多少头母牛?

输入格式

输入包括一个整数 n(0 < n < 55)。

输出格式

输出在第 n 年的时候母牛的数量。 

Sample 1

InputcopyOutputcopy
2
2

Sample 2

InputcopyOutputcopy
5
6

递归: 从第五年开始, 第二年生的母牛开始生小牛, f(n)=f(n-1)+f(n-3)

#include<stdio.h>
int cow(int n);
int main()
{
    int n;
    scanf("%d", &n);
    printf("%d", cow(n));
    return 0;
}

int cow(int n)
{
    if (n <= 4) return n;
    else return cow(n - 1) + cow(n - 3);
    return 0;
}

L - 授勋

历经旷日持久的战争之后,百纳瑞王国(The Kingdom of Binary)终于迎来了胜利的曙光。于是国王决定在胜利日这一天为在战争中奋战的将领们授勋。

已经需要为N位将领授勋,他们每人有一个功勋值p[i]。国王准备了不同种类的勋章,它们分别代表1,2,4,8,16......(即2的幂次)的功勋值。国王将用与每位将领功勋值对等数值的勋章授予他们,并且每位将领只会被授予一枚同种勋章

现在请你帮助国王算出,对于每一位将领,他需要准备多少枚勋章?

Input

第一行输入一个数N,表示将领人数; 之后N行,每行输入一个数,分别表示每位将领的功勋值。

Output

输出N行,每行一个数表示需要授予该将领的勋章数。

Sample

InputcopyOutputcopy
3
15
1
22
4
1
3

将十进制数转化为二进制数的过程中, 计算出现1的个数

#include<stdio.h>
int a[100005], b[100005];
int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
		scanf("%d", &a[i]);
	for (int i = 0; i < n; i++)
	{
		while (a[i])
		{
			if (a[i] % 2 == 1) //a[i]为1 计数加1
			{
				b[i]++;
				a[i] /= 2;
			}
			else 
			{
				a[i] /= 2;
			}
		}
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d\n", b[i]);
	}

	return 0;
}

 

M - 完美立方

形如 a^3= b^3 + c^3 + d^3 的等式被称为完美立方等式。

例如 12^3= 6^3 + 8^3 + 10^3。

编写一个程序,对任给的正整数 N(N≤100),寻找所有的四元组 (a, b, c, d),使得 a^3 = b^3 + c^3 + d^3,其中 a,b,c,d 大于 1,小于等于 N,且 b≤c≤d。

输入格式

一个正整数 N(N≤100)。

输出格式

每行输出一个完美立方。输出格式为:

Cube = a, Triple = (b,c,d)

其中 a,b,c,d 所在位置分别用实际求出四元组值代入。

请按照 a 的值,从小到大依次输出。当两个完美立方等式中 a 的值相同,则 b 值小的优先输出;仍相同则 c 值小的优先输出;再相同则 d 值小的先输出。

Sample 1
Inputcopy    Outputcopy
24
Cube = 6, Triple = (3,4,5)
Cube = 12, Triple = (6,8,10)
Cube = 18, Triple = (2,12,16)
Cube = 18, Triple = (9,12,15)
Cube = 19, Triple = (3,10,18)
Cube = 20, Triple = (7,14,17)
Cube = 24, Triple = (12,16,20) 

注意循环起始数, 控制  b≤c≤d 

#include<stdio.h>
int i;
int n;
int a, b, c, d;

int main()
{
	
	scanf("%d", &n);
	for (i = 2; i <= n; i++)
	{
		for (int j = 2; j <= n; j++)
		{
			for (int k = j; k <= n; k++)
			{
				for (int x = k; x <= n; x++)
				{
					a = i * i * i;
					b = j * j * j;
					c = k * k * k;
					d = x * x * x;
					if (a == b + c + d)
						printf("Cube = %d, Triple = (%d,%d,%d)\n", i, j, k, x);
				}
			}
		}
	}

	return 0;
}

P - 两个子序列

学习了字符串相关知识的王大队长在思考一些问题:现在王大队长有一个字符串 s ,他想找到两个非空字符串 a and b ,来满足下面的条件:

  1. 字符串 a 和 b 都是 s 的子序列;
  2. 对于每个索引 i, 字符串 s 的字符 si​ 必须恰好属于字符串 a 或 b 其中一个;
  3. 字符串 a 必须是字典序 最小的,字符串 b 则可以是任何可能的字符串;

现在给定字符串 ss, 请打印出任意一组有效的 a 和 b.

Input

每个测试包含多个测试用例。第一行包含测试用例的数量 t (1≤t≤1000). 测试用例的描述如下:

每个测试用例的第一行也是唯一一行包含一个字符串 s (2≤∣s∣≤100 其中 ∣s∣ 表示 s 的长度). 字符串 s 由小写拉丁字母组成。

Output

对于每个测试用例,打印满足给定条件的字符串 a 和 b ,如果有多个答案,请输出任意一个。

Example

Input

3
fc
aaaa
thebrightboiler

Output

c f
a aaa
b therightboiler

注意审题! 先输出字符串中最小的字母, 后输出不包含这个字母的任意子串

#include<stdio.h>
#include<string.h>
int main()
{
	int t;
	scanf("%d", &t);
	char a[100];

	while (t--)
	{
		char min = 'z'; //设置最小的字母
		scanf("%s", a);
		int len = strlen(a);
		for (int i = 0; i < len; i++)
		{
			if (a[i] < min)
			{
				min = a[i];
			}
		}
		printf("%c ", min);
		for (int i = 0; i < len; i++)
		{
			if (a[i] == min) //找到最小的字母
			{
				for (int x = i; x < len - 1; x++)
					a[x] = a[x + 1]; //把后面的子串赋给现在的子串, 覆盖住
				len--; //长度减1, 相当于在之后的输出中不输出这个字母
				break; 
			}
		}
		for (int i = 0; i < len; i++)
		{
			printf("%c", a[i]); //放入循环中, 一个一个输出
		}
		printf("\n");

	}
	return 0;
}

Q - 轻重搭配

n 个同学去动物园参观,原本每人都需要买一张门票,但售票处推出了一个优惠活动,一个体重为 x 的人可以和体重至少为 2x 配对,这样两人只需买一张票。现在给出了 n 个人的体重,请你计算他们最少需要买几张门票?

输入格式

第一行一个整数 n,表示人数。

第二行 n 个整数,每个整数 ai​ 表示每个人的体重。

输出格式

一个整数,表示最少需要购买的门票数目。

数据范围

对于 30% 的数据:1≤n≤25,1≤ai​≤100。

对于 60% 的数据:1≤n≤10000,1≤ai​≤1000。

对于 100% 的数据:1≤n≤5*10^5,1≤ai​≤10^5。

样例解释

1 和 9 配对,7 和 3 配对,剩下 5,5 单独,一共买四张票。

Sample 1

InputcopyOutputcopy
6
1 9 7 3 5 5
4

 把数据分为两半, 看前一部分的最大值能否与后一部分的最大值配对

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int a[500005], b[500005] = { 0 };
int main()
{
	int n, i, j, t = 0, l = 1;
	scanf("%d", &n);
	int mid = n / 2; //找到中间值
	int r = n;
	for (i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	sort(a, a + 1 + n);
	while (mid)
	{
		if (a[mid] * 2 <= a[r])
		{
			t++;
			mid--;
			r--;
		}
		else mid--;
	}
	printf("%d", n-t);
	return 0;
}

 R - 最小新整数

给定一个十进制正整数 n(0 < n < 1000000000),每个数位上数字均不为 0。n 的位数为 m。
现在从 m 位中删除 k 位 (0<k < m),求生成的新整数最小为多少?
例如: n = 9128456, k = 2,  则生成的新整数最小为 12456。

输入格式

第一行 t, 表示有 t 组数据;
接下来 t 行,每一行表示一组测试数据,每组测试数据包含两个数字 n, k。

输出格式

t 行,每行一个数字,表示从 n 中删除 k 位后得到的最小整数。

Sample 1

InputcopyOutputcopy
2
9128456 2
1444 3
12456
1

找到前一位比后一位大的数, 让后面的覆盖住前面的, 长度减1, 相当于把这个数删除了 

#include<stdio.h>
#include<string.h>
int main()
{
	int t,k,i,j,x;
	char a[20];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%s %d",a,&k);
		int len=strlen(a);
		for(i=0;i<k;i++)
		{
			for(j=0;j<len-1;j++)
			{
				if(a[j]>a[j+1])
				{
					for(x=j;x<len-1;x++)
					{
						a[x]=a[x+1];
					}
					break;
				}
			}
			len--;
		}
		for(i=0;i<len;i++)
		{
			printf("%c",a[i]);
		}
		printf("\n");
	}
	
	
	return 0;
 } 

T - 小孩报数问题

有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。

Input

第一行输入小孩的人数N(N<=64)
接下来每行输入一个小孩的名字(人名不超过15个字符)
最后一行输入W,S (W < N),用逗号","间隔

Output

按人名输出小孩按顺序出列的顺序,每行输出一个人名

Sample

InputcopyOutputcopy
5
Xiaoming
Xiaohua
Xiaowang
Zhangsan
Lisi
2,3
Zhangsan
Xiaohua
Xiaoming
Xiaowang
Lisi

约瑟夫环问题 ,可以用单链表或循环链表解决

单链表: 

#include<stdio.h>
#include<iostream>
using namespace std;

typedef struct Child
{
	char name[100];
	struct Child* next;
}child;

int main()
{
	int n, w, s, i, j;
	scanf("%d", &n);
	child* head=NULL, * p=NULL, * q=NULL, * r;
	for (i = 0; i < n; i++)
	{
		r = (child*)malloc(sizeof(child));
		scanf("%s", r->name);
		if (p == NULL)
		{
			head = r;
			p = head;
		}
		else
		{
			p->next = r;
			p = r;
		}
	}
	scanf("%d,%d", &w, &s);
	p->next=head;
	p = head;
	for (i = 1; i < w; i++)
		p = p->next;
	q = p;
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j < s; j++)
		{
			q = p;
			p = p->next;
		}
		printf("%s\n", p->name);
		q->next = p->next; //跳过这个节点
		p = q->next; //继续新的遍历
	}
	return 0;
}

 循环双向链表:

#include<iostream>
#include<cstring>
using namespace std;
struct List//双向链表结构体
{
	char name[20];
	struct List *front;//前指针
	struct List *rear;//后指针
};

List* create(int n)//构造函数
{
	List *node,*head;
	head = node = new List;
	for(int i = 2;i <= n;++i)
	{
		node->rear = new List;
		node->rear->front = node;
		node = node->rear;
	}
	node->rear = head;
	head->front = node;
	return head;
}
List* move(List* p,int step)//链表计数移动
{
	for(int i = 1;i < step;++i)
	{
		p = p->rear;
	}
	return p;
}
List* remove(List *p)//删除节点操作,双向链表的关键所在
{
	p->front->rear = p->rear;
	p->rear->front = p->front;
	p = p->rear;
	return p;
}
int main()
{
	int n,w,s;
	scanf("%d",&n);
	List *node,*head;
	head = node = create(n);
	
	for(int i = 1;i <= n;++i)
	{
		scanf("%s",node->name);//读入结点名字
		node = node->rear;
	}
	scanf("%d,%d",&w,&s);
	node = move(head,w);
	while(node->rear != node)//循环链表的遍历终止条件
	{
		node = move(node,s);
		printf("%s/n",node->name);
		node = remove(node);
	}
	printf("%s/n",node->name);//剩下最后一个结点时要输出
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值