前言
这个比赛真的唐完了!!!!!
虽然就写了一个小时(前一个小时去和朋友吃饭了),但是就过了两题你敢信,真的不难的说
待我与你细细说来 我的唐人史
正文
1 桃园结义
打卡题,输出3即可,毕竟桃园三结义嘛
#include <iostream>
using namespace std;
int main()
{
cout<<3;// 请在此输入您的代码
return 0;
}
2 北伐军费
这个题和之前cf上一道题有点像
每个人都会拿当前的最大值,但是这个是每次拿他都会乘-1
不过我们可以发现其实选了两次之后就会变成原数组,比如1 2 3
A 选3,变成-1 -2 然后B选-1 变成 2,其实还是选的原来的数组
因此 对于A 来说他会选原数组的最大的,对于B来说,他会选原数组相反数的最大的(也就是最小的),所以其实可以进行排序后A从大到小加,B从小到大加 小的数的相反数(对于他就是大的)
然后最后A-B
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int n;
cin >> n;
int s1 = 0, s2 = 0, a[10000];
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n / 2; i++) {
s1 += -a[i];
s2 += a[n - i + 1];
}
if (n % 2)
s2 += a[(int)n / 2 + 1];
cout << s2 - s1 << endl;
return 0;
}
但是还没完哈,赛后我看了看其他人的代码,发现一个更妙的做法,我们对于B是每次加原数组的一个相反数,然后我们最后又进行A-B,那么其实B又反回来了,所以其实最后的答案就是数组和
(对的没错,就是数组和,自己推一下就可以看出来了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int n;
cin >> n;
int s,x;
s=0;
for (int i = 1; i <= n; i++) {
cin >> x;s+=x;
}
cout<<s;
return 0;
}
3 挑选武将
从这里就开始唐B了,,,难绷
题干的意思是 最多有多少个单独来自一个军营的士兵
我以为的意思 最少有多少个士兵来自同一军营
一直调过不了啊!!!!题干读错了真滴难绷
然后这个题也是不难,首先每个人来自军营的编号并不重要,我们可以把他们存起来,然后降序排序,并且为了确保尽可能多的的士兵是单独的,我们尽量先把人最多的营的士兵都找过来,这样就可以尽可能减少对不同兵营的消耗,就是这样
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int num[100005];
int main() {
int x, n, k, sum, r, ans = 0;
cin >> n >> k;
for (int i = 0; i < n; i++) {
cin >> x;
num[x]++;
}
sort(num, num + 100003, greater<int>());
for (int i = 100002; i >= 0; i--)
if (num[i]) {
ans = r = i + 1;
break;
}
if (ans >= k) {
cout << k << endl;
return 0;
}
k -= ans;
for (int i = 0; i <= r; i++) {
ans--;if (k - num[i] + 1 <= 0)
break;
k = k - num[i] + 1;
}
cout << ans;
return 0;
}
4 三顾茅庐
这道题我也看了,但是唐的更离谱。。。
这个题如果都是x减完以后如果都是正的就直接输出即可,关键在于如果会减到负数怎么办捏
首先我们可以把x减到最小的正数,也就是再减就会变成负数的情况,此时一定会有x<y
那么如果这时候再进行|x-y|,实际上就会变成y-x,然后对于y-x,如果再进行y-(y-x)就会变成x
不难发现这里是一个循环
所以我们其实需要看这个时候的k剩下的如果是奇数那么最后就会剩一个y-x否则就是x
然后就过了,那么为什么会唐呢?
这里是一个多组 我在特判的时候直接进行break操作了!!!!!
真的受不了赛后改成continue就对了,以后多组还是直接外接slove函数直接return 吧呜呜呜
5 逆天改命
这个其实就是对一个0数组进行操作来看可不可以到一个新的数组
然后有区间有0才能加,区间可以随便减
那么其实我们完全可以对一个数进行减的操作,使他减到合适的数,所以我们可以先把数组都变得很大,然后再每个自己去减
但是我们发现有0才能加啊,所以需要有一个数做出贡献,一直对自己进行减的操作变成0,然后别的数都满足了以后,这个0最多可以自己加到1,所以有一个数最多是1,其他都可以
结论就是,如果数组有0或者1那么就是OK,否则就不行
#include <iostream>
using namespace std;
int main() {
int t, s, x, n;
cin >> t;
while (t--) {
cin >> n;
s = 0;
while (n--) {
cin >> x;
if (x == 1 || x == 0)
s = 1;
}
if (s)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
// 请在此输入您的代码
return 0;
}
6 智算士气
这道题用到了质因数分解的思想
首先我们需要知道 任何一个数都可以被分解成,k个质数相乘的形式
pi^ai 从1k连乘的形式 那么对于每一个pi,我们都可以选择取m个pi (0<=m<=ai)那么就有1+ai种可能 然后有n个队伍要取 所以一共有 (1+ai)^n种情况
但是他需要所有数的最小公倍数是m,那么我们还需要保证对于每个质数pi 都有一个数把他选到pi^ai的形式,只有这样所有数的最小公倍数才会是m
所以对于每个质数,我们真正可以取得情况是(1+ai)^n-ai^n
也就是从0~ai里面去掉只选0~(ai-1)的情况,就是至少有一个数选ai的情况数 然后对于每个pi的情况都乘起来就是ans了
但是注意取模过程要用快速幂,而且在计算的过程也要实时取模,不然一定会wa掉,好像还要开ll
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
ll fpow(ll n, ll k) {
ll res = 1;
while (k) {
if (k & 1)
res = res * n % mod;
n = n * n % mod;
k >>= 1;
}
return res;
}
int main() {
ll n, m, s, ans = 1;
cin >> n >> m;
for (int i = 2; i <= m / i; i++) {
if (m % i == 0) {
int s = 0;
while (m % i == 0)
m /= i, s++;
ans = (ans % mod * (fpow(s + 1, n) - fpow(s, n)) % mod + mod) % mod;
}
}
if (m > 1)
ans = (ans % mod * (fpow(2, n) - fpow(1, n)) % mod + mod) % mod;
cout << ans % mod << endl;
return 0;
}
PS:这里我想说一个问题,取模经常要用(x%mod+mod)%mod
这个为什么呢?
其实就是为了防负数出现,那我们为啥会有负数出现呢?
拿这个题举例,虽然好像(1+ai)^n-ai^n一定是正的啊, 但是我们在快速幂的时候,取模后的模数就不清楚到底哪个大了,就可能出现负数的情况,所以还是要取模滴
后记
这个比赛真的蚌埠住了,这么简单的题.....
不过会了就好,继续补题吧,这个也给我一个很真实的警告,编程容不得半点差错啊!!!
望诸君共勉