凑算式
这个算式中A ~ I代表1 ~ 9的数字,不同的字母代表不同的数字
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
解题思路:因为C++中除法为整除,所以我们应该先将后两个分式通分判断,用dfs暴力搜出所有情况判断即可
#include <iostream>
using namespace std;
int a[10], ans;
bool visit[10];
bool check(void)
{
int b = a[1], c = a[2], d = a[3] * 100 + a[4] * 10 + a[5], g = a[6] * 100 + a[7] * 10 + a[8];//预处理两个分数的分子分母
int x = b * g + c * d;//预处理通分后的分子分母
int y = c * g;
if((a[0] + x / y == 10) && x % y == 0) return true;//判断
else return false;
}
void dfs(int u)//dfs暴力搜索
{
if(u == 9)
{
if(check()) ans++;
return ;
}
for(int i = 1; i <= 9; i++)
{
if(!visit[i])
{
visit[i] = true;
a[u] = i;
dfs(u + 1);
visit[i] = false;//回溯
}
}
return ;
}
int main(void)
{
dfs(0);
cout << ans << endl;
return 0;
}
答案为:29
四平方和
题目描述
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 4 个正整数的平方和。
如果把 0 包括进去,就正好可以表示为 4 个数的平方和。
比如:
5=02+02+12+22
7=12+12+12+22
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 4 个数排序:
0≤a≤b≤c≤d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
输入格式
输入一个正整数 N。
输出格式
输出4个非负整数,按从小到大排序,中间用空格分开。
数据范围
0< N < 5 ∗ 1 0 6 10^6 106
输入样例
5
输出样例
0 0 1 2
解题思路:由题意得 a <= b <= c <= d,所以我们如果暴力三重循环做时间复杂度为 n / 2 ∗ n / 3 ∗ n / 2 ∗ n 复 杂 度 为 O ( n 2 ) \sqrt{n}/2 * \sqrt{n/3} * \sqrt{n/2} * \sqrt{n}复杂度为O(n^2) n/2∗n/3∗n/2∗n复杂度为O(n2)n为 1 0 6 10^6 106显然超时, 于是我们可以通过预处理 C 2 + D 2 C^2 + D^2 C2+D2来降低时间复杂度
- 建立哈希表储存小于n的数c,从小到大遍历c, d,储存先出现的c, d
- 从小到大便利a, b,查找1中建立的哈希表若存在则算出d
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1e7;
int n, h[N];
int main(void)
{
cin >> n;
for(int c = 0; c * c * 2 <= n; c++)
{
for(int d = c; d * d + c * c <= n; d++)
{
if(!h[d * d + c * c]) h[d * d + c * c] = c + 1;//防止跳过为0的情况
}
}
//a <= b <= c <= d 所以 a * a <= n / 4 a * a + b * b <= n / 2
for(int a = 0; a * a * 4 <= n; a++)
{
for(int b = a; (b * b + a * a) * 2 <= n; b++)
{
int t = n - b * b - a * a;
if(h[t] > 0)
{
int c = h[t] - 1;
int d = (int)(sqrt(n - b * b - a * a - c * c) * 1.0);
cout << a << ' ' << b << ' ' << c << ' ' << d << endl;
return 0;
}
}
}
return 0;
}
交换瓶子
题目描述
有 N 个瓶子,编号 1∼N,放在架子上。
比如有 5 个瓶子:
2 1 3 5 4
要求每次拿起 2 个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5
对于这么简单的情况,显然,至少需要交换 2 次就可以复位。
如果瓶子更多呢?你可以通过编程来解决。
输入格式
第一行包含一个整数 N,表示瓶子数量。
第二行包含 N 个整数,表示瓶子目前的排列状况。
输出格式
输出一个正整数,表示至少交换多少次,才能完成排序。
数据范围
1≤N≤10000
输入样例1
5
3 1 2 5 4
输出样例1
3
输入样例2
5
5 4 3 2 1
输出样例
2
解题思路:首先由样例1: 3 1 2 5 4 转为:1 2 3 4 5
- 3对应3号位即2所在位置
- 2对应2号位即1所在位置
- 1对应1号位即3所在位置
这样就构成了一个环,这样的环共有两个
环内两个点的变动可以使环分裂为二
环外两个点的变动可使两个环合二为一
正确顺序即存在n个环
通过计算环的个数k,每一次交换都能使环数+1,我们想从k个环到n个环即需要n - k次交换
#include <iostream>
using namespace std;
const int N = 10010;
int n, a[N], k;
bool visit[N];//用于记录是否在环中被计算
int main(void)
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
for(int i = 1; i <= n; i++)
{
if(!visit[i])//如果没有走过
{
k++;//环个数+1
for(int j = i; !visit[j]; j = a[j])//遍历这个环中所有的点并标记
{
visit[j] = true;
}
}
}
cout << n - k << endl;
return 0;
}