`#include<iostream>
using namespace std;
int main()
{
int a = 1, b = 1, c = 1, res = 0;
for(int i = 4; i <= 20190324; ++i)
{
res = (a + b + c) % 10000;
a = b;
b = c;
c = res;
}
cout << res << endl; // 答案4659
return 0;
}`
4D:数的分解(填空10分)
题目描述:
把 2019分解成 3个各不相同的正整数之和,并且要求每个正整数都不包
含数字2和4,一共有多少种不同的分解方法?
注意交换 3个整数的顺序被视为同一种方法,例如 1000+1001+18和
1001+1000+18被视为同一种。
答案40785
cpp复制代码
#include <iostream>
using namespace std;
bool have_24(int x)
{
while (x)
{
if (x % 10 == 2 || x % 10 == 4)
return true;
x /= 10;
}
return false;
}
int main()
{
int res = 0;
for (int i = 1; i < 2019; ++i)
{
if (!have_24(i))
for (int j = i + 1; j < 2019; ++j)
{
if (have_24(j))
continue;
int k = 2019 - i - j;
if (!have_24(k) && k > j) // i j k 从小到大
++res;
}
}
cout << res << endl; // 答案40785
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
#define int long long
#define endl '\n'
// n比较大,会爆因子
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n = 2021041820210418;
vector<int> v;
for (int i = 1; i * i <= n; i++) // 得到n的所有约数
{
if (n % i == 0)
{
v.push_back(i);
if (n / i != i)
v.push_back(n / i);
}
}
//cout << v.size() << endl;
int res = 0;
for (auto& a : v) //枚举一下a b c
{
for (auto& b : v)
{
for (auto& c : v)
{
if (a * b * c == n)
++res;
}
}
}
cout << res << endl;
return 0;
}
// 答案:2430
#include <iostream>
using namespace std;
bool have_2019(int x)
{
while (x)
{
int a = x % 10;
if (a == 2 || a == 0 || a == 1 || a == 9)
return true;
x /= 10;
}
return false;
}
int main()
{
int n = 0, sum = 0;
cin >> n;
for (int i = 1; i <= n; ++i)
{
if (have_2019(i))
{
sum += i;
}
}
cout << sum << endl;
return 0;
}
7G:完全二叉树的权值(编程题20分)
解析代码(二叉树的数组遍历)
cpp复制代码
#include<iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
long long arr[N];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
}
int maxv = -INF;
int depth = 1, res = 1;
for (int i = 1; i <= n; i *= 2)
{
long long s = 0; // 完全二叉树每层的开头为2^(n-1),结尾则是 2^n - 1
for (int j = i; j <= i * 2 - 1 && j <= n; j++) // j++就是同一层的下一个
{
s += arr[j];
}
if (s > maxv)
{
maxv = s;
res = depth;
}
depth++;
}
cout << res << endl;
return 0;
}
8H:等差数列(编程题20分)
题目描述:
数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中 N 个整数。现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?
【输入格式】
输入的第一行包含一个整数 N。
第二行包含 N 个整数 A 1 ,A 2 ,··· ,A N 。(注意 A 1 ∼ A N 并不一定是按等差数
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a, a + n); // 排序是为了让首项为a[0]
int d = 0; // 0与任何数的最大公约数都是它的本身
for (int i = 1; i < n; i++)
{
//d = gcd(d, a[i] - a[0]); // 减去首项a1
d = __gcd(d, a[i] - a[0]); // 减去首项a1,Linux或另一些编译器能用,蓝桥杯也能,VS2022不能
}
if (!d)
printf("%d\n", n); // 如果公约数为0.那么就证明这时一个常数数列
else
printf("%d\n", (a[n - 1] - a[0]) / d + 1); // 公式
return 0;
}
9I:后缀表达式(编程题25分)
题目描述:
给定 N 个加号、M 个减号以及 N + M + 1 个整数 A 1 ,A 2 ,··· ,A N+M+1 ,小
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define int long long
#define endl '\n'
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n = 0, m = 0;
cin >> n >> m;
int k = n + m + 1; // n = k - m - 1
vector<int> arr(k);
for (int i = 0; i < k; ++i)
{
cin >> arr[i];
}
int sum = 0;
if(m == 0)
{
for (int i = 0; i < k; i++)
{
sum += arr[i];
}
}
else // 有负号,能把负数变为正数
{
sort(arr.begin(), arr.end());
//int index = 0; // 百分之70的分
//while (arr[index] < 0 && m--)
//{
// sum += -arr[index++];
//}
//while (m--)
//{
// sum -= arr[index++];
//}
//while(index < k)
//{
// sum += arr[index++];
//}
sum = arr[k - 1] - arr[0]; // 只保留一个减号
for (int i = 1; i < k - 1; i++)
{
sum += abs(arr[i]);
}
}
cout << sum << endl;
return 0;
}
10J:灵能传输(编程题25分)
【样例输入】
3
3
5 -2 3
4
0 0 0 0
3
1 2 3
【样例输出】
3
0
3
【样例说明】
对于第一组询问:
对 2 号高阶圣堂武士进行传输操作后 a1 = 3,a2 = 2,a3 = 1。答案为 3。
对于第二组询问:
这一组高阶圣堂武士拥有的灵能都正好可以让他们达到最佳战斗状态。
【样例输入】
3
4
-1 -2 -3 7
4
2 3 4 -8
5
-1 -1 6 -1 -1
【样例输出】
5
7
4
解析代码(前缀和+贪心)
该题实际上要求通过何种灵能传输可以使得该序列的最大值最小
而由前缀和可知 一个有序的前缀和序列 其max(s[i]-s[i-1])的最大值可以达到最小
(关于这个点大家可以画个图理解一下)
通过对几个样例的观察可以发现一个规律
1.对于ai有
1.a[i]>0时 a[i-1]=a[i-1]+a[i] 则 s[i-1]= 原来的s[i]
a[i]=a[i]-2*a[i] 则 原s[i]= s[i-1] + a[i]
则 现s[i]= 现s[i-1] - a[i]= 原s[i]- a[i]=原s[i-1]
a[i+1]=a[i+1]+a[i] 参考上述推导 可得 s[i+1]=原s[i+1]
这意味着除了s[0]和s[n]以外1~n的任何s[i]可以进行相互交互从而得到一个有序的序列
而a[i]=s[i]-s[i-1]
也就意味着可以通过交换s[i]的方式得到灵能传输后最终结果
cpp复制代码
for (int i = 1;i <= n;i++)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
sort(s, s + 1 + n);
如果s[0],s[n]也可以正常交换的话那么这题的推导到这步就可以结束了
我们可以通过直接计算max(s[i]-s[i-1]的值 获得最大值的最小值
但问题在于 s[0],s[n]
即我们最终得到的一个序列并不一定是单调的
所以接下来我们就要通过一系列操作解决不单调序列的问题
2.通过上述分析可以明确想要求得本题的最优解应使得所求序列尽量保持单调
通过画图可知一个有两个拐点的曲线重叠部分最小时 单调部分最多
而一个曲线符合下列情况时符合要求:
1.左端点小于右端点 即要求s[0]<s[n]
cpp复制代码
LL s0 = s[0], sn = s[n];
if (s0 > sn)
swap(s0, sn);
2.极小值在极大值左边
该点要求我们在后续选点的时
应s[0]向左取 s[n]向右取 因为只有这样才能取得两边的极值
cpp复制代码
int l = 0, r = n; // 构造重叠部分最小的序列
for (int i = s0; i >= 0; i -= 2)
{
f[l++] = s[i], st[i] = true;
}
for (int i = sn; i <= n; i += 2)
{
f[r--] = s[i], st[i] = true;
}
for (int i = 0; i <= n; ++i)
{
if (st[i] == false)
f[l++] = s[i];
}
这样以后就可以保证序列为f为重叠部分最小的前缀和序列
cpp复制代码
LL res = 0;
for (int i = 1;i <= n;i++)
{
res = max(res, abs(f[i] - f[i - 1]));
}
cout << res << endl;
res即为所求结果,以下为完整代码。
cpp复制代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 3e5 + 10;
#define endl '\n'
//由于a[]可能达到1e9所以需要使用到LL
typedef long long LL;
LL a[N]; //用于存放初始灵能值
LL s[N]; //用于存放前缀和
LL f[N]; //用于存放最终的有序序列
bool st[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--)
{
int n;
cin >> n;
s[0] = 0;// 注意这一步不要忘了
for (int i = 1;i <= n;i++)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
LL s0 = s[0], sn = s[n];
if (s0 > sn)
swap(s0, sn);
sort(s, s + 1 + n);
for (int i = 0; i <= n; ++i) // 找到排序后 s0,sn的位置
{
if (s0 == s[i])
{
s0 = i;
break;
}
}
for (int i = 0; i <= n; ++i)
{
if (sn == s[i])
{
sn = i;
break;
}
}
memset(st, false, sizeof st);
int l = 0, r = n; // 构造重叠部分最小的序列
for (int i = s0; i >= 0; i -= 2)
{
f[l++] = s[i], st[i] = true;
}
for (int i = sn; i <= n; i += 2)
{
f[r--] = s[i], st[i] = true;
}
for (int i = 0; i <= n; ++i)
{
if (st[i] == false)
f[l++] = s[i];
}
LL res = 0;
for (int i = 1;i <= n;i++)
{
res = max(res, abs(f[i] - f[i - 1]));
}
cout << res << endl;
}
return 0;
}