前天进行了第一次测试,一共10道题只写出来6道题,题目本身难度不大,基本没什么算法,除了最后两道题目考察了双指针(滑动窗口)和深度搜索,但也仅仅只写出来了6道,还是太菜了
对于题目G和H这两道思维题也是没写出来,学的太死板,每次这种思维类的题目都不会写。
我们定义n个整数的全排列 p 为 1, 2, ..., n (1~n每个数出现且只出现一次,顺序任意) ,定义全排列的价值X如下:
例如, 对于全排列 p=[4,5,1,2,3,6],价值 x在计算过程中的所有值如下: 0,4,9,0,2,5,11, 所以全排列的价值为 11.
给你一个整数 n. 请找出一个 n的全排列 p 使得其在n的所有全排列中价值最大. 如果有多种符合要求的全排列,输出任意一种.
输入
输入的第一行包含一个整数 t (1≤t≤97) — 测试样例的数量.
每个测试样例的输入仅包含一个整数 n (4≤n≤100),占据一行.
输出
对于每组测试样例, 输出 n 个整数 — 价值最大的n的全排列p .
输入案例
3 4 5 6
2 1 3 4 1 2 3 4 5 4 5 1 2 3 6
对于这一道题当时看到是全排列,第一想法是深搜,然而看了数据后感觉深搜很可能会超时,最后果然不出所料,之前也隐隐猜到了有什么规律,可惜实力不济没找到,
根据题解
答案一定是2*n-1,这里不知道为什么是这样,但也找不到反例,然后要做的操作是如何排列使答案最大价值为2*n-1,使最大价值为2*n-1只要最后两个数是n-1和n然后前面的所有数互相抵消就行了,这里要分奇数还是偶数,如果是偶数直接两个两个为一组前面的数大于后面的数就行,如果是奇数则消耗一个数再两个两个一组消耗掉,除了最后两个数。
代码如下:
#include
int main()
{
int t, n;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
if (n % 2 == 0)//如果是偶数
{
for (int i = 1; i <= n - 2; i = i + 2)//两两一组前面的大于后面的
{
printf("%d %d ", i + 1, i);
}
printf("%d %d\n", n - 1, n);//最后输出最后两个数
}
else//如果是奇数
{
printf("1 ");//先输出1
for (int i = 2; i <= n - 2; i = i + 2)//再两两一组互相抵消
{
printf("%d %d ", i + 1, i);
}
printf("%d %d\n", n - 1, n);
}
}
return 0;
}
机器人被放置在一个网格的左上角,由n行和m列组成,在单元格(1,1)。
在一步中,它可以移动到相邻的单元格,旁边有一边是当前的单元格:
机器人不能移出网格。
单元格(sx,sy)包含一个致命的激光。如果机器人进入到距离激光小于或等于d的单元格,它就会被蒸发。两个单元格(x1,y1)和(x2,y2)之间的距离为|x1−x2|+|y1−y2|。
打印机器人可以在不被蒸发或移出网格的情况下到达单元格(n,m)所需的最小步数。如果无法到达单元格(n,m),则打印-1。
激光既不在起始单元格,也不在结束单元格。起始单元格与激光的距离始终大于d。
输入
第一行包含一个整数t(1≤t≤10^4)— 测试用例的数量。
每个测试用例的唯一一行包含五个整数n,m,sx,sy,d(2≤n,m≤1000;1≤sx≤n;1≤sy≤m;0≤d≤n+m)— 网格的大小,包含激光的单元格和激光的蒸发距离。
激光既不在起始单元格,也不在结束单元格((sx,sy)≠(1,1)和(sx,sy)≠(n,m)。起始单元格(1,1)与激光的距离始终大于d(|sx−1|+|sy−1|>d)。
输出
对于每个测试用例,打印一个整数。如果可以从(1,1)(1,1)到达单元格(n,m)(�,�),而不被蒸发或移出网格,则打印机器人到达目标所需的最小步数。否则,打印-1。
示例1
Input | Output |
---|---|
3 2 3 1 3 0 2 3 1 3 1 5 5 3 4 1 |
3 -1 8 |
这一题的最短路径是固定的(当时还傻傻的用广搜找最短路径结果超时),只需要判断能不能到达终点就行了。
代码如下
#include
#include
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, m, sx, sy, d, i, j, flag = 0;
scanf("%d %d %d %d %d", &n, &m, &sx, &sy, &d);
if (abs(sx - n) + abs(sy - m) <= d)//如果覆盖终点
{
printf("-1\n");
continue;
}
//如果不能到达终点
if ((sx - 1 <= d && sy - 1 <= d) || (sx - 1 <= d && n - sx <= d) || (m - sy <= d && sy - 1 <= d) || (n - sx <= d && m - sy <= d))
{
printf("-1\n");
continue;
}
printf("%d\n", n + m - 2);
}
return 0;
}
Description
对一个给定的正整数 M,求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为 M。
例子:1998+1999+2000+2001+2002=10000,所以从 1998 到 2002的一个自然数段为 M=10000 的一个解。
Input
包含一个整数的单独一行给出 M 的值(110≤M≤2,000,000)。
Output
每行两个正整数,给出一个满足条件的连续正整数段中的第一个数和最后一个数,两数之间用一个空格隔开,所有输出行的第一个按从小到大的升序排列,对于给定的输入数据,保证至少有一个解。
Sample 1
Input | Output |
---|---|
10000 |
18 142 297 328 388 412 1998 2002 |
解题思路
本题可以用两个指针指向范围的左边和右边,快指针一旦移动到快指针与慢指针区间大于等于m的时候结束再判断是否等于m如果等于输出慢指针和快指针的值,再移动慢指针。
代码如下
#include
int main()
{
int m, i, j = 1, he = 0;
scanf("%d", &m);
for (i = 1; i < m && i <= j; i++)//i为慢指针
{
while (he < m && j < m)//j为快指针,保证区间小于内he小于m
{
he += j;
j++;
}
if (he == m)//如果等于m输出结果
{
printf("%d %d\n", i, j - 1);
}
he -= i;//慢指针移动
}
return 0;
}
问题描述
一个重复数是一个在十进制表示中所有数字都是1的整数。按升序排列的重复数是1,11,111,…。
找到可以表示为恰好三个重复数之和的第N小的整数。
约束条件
输入
输入以以下格式从标准输入中给出:
N
输出
输出答案。
示例 1
Input | Output |
---|---|
5 |
113 |
可以表示为恰好三个重复数之和的整数按升序排列为3,13,23,33,113。例如113可以表示为113=1+1+111。
请注意,这三个重复数不必互不相同。
示例 2
Input | Output |
---|---|
19 |
2333 |
示例 3
Input | Output |
---|---|
333 |
112222222233 |
解题思路
本题是用深度搜索后,然后再升序排列,求出第n大小的数,这里大概要组合1400左右多的数再排列才能满足n为333的时候。
#include
long long book[20], a[20] = { 0,1 }, sum = 0, n, h = 0, c[1000000] = { 0 };
void dfs(long long x,long long y)//dfs组合问题
{
if (x == 4)//dfs深度为3 当组合有三个数的时候直接返回
{
h++;
c[h] = sum;
return;
}
long long i;
for (i = y; i <= 18; i++)
{
if (book[i] < 3)//每个数最多可以使用三次
{
book[i]++;
sum += a[i];
dfs(x + 1, i);
book[i]--;//回溯
sum -= a[i];
if (h == 1400)//大概求出1400作用的组合可以满足n等于333的时候
return;
}
}
}
int main()
{
for (int i = 2; i <= 18; i++)//预处理重复数
a[i] = a[i - 1] * 10 + 1;
scanf("%lld", &n);//输入n
dfs(1,1);
for (int i = 1; i < h; i++)//选择排序
{
for (int j = i + 1; j <= h; j++)
{
if (c[i] > c[j])
{
long long t = c[i];
c[i] = c[j]; c[j] = t;
}
}
}
printf("%lld", c[n]);//输出结果
return 0;
}