一.数字降级
1.1 问题描述
数字每一次降级都表示将一个数字除以一次它的任意一个因子。请问最少几次操作可以将一个数字 ,降级成一个质数?
例如:数字 ,第一种方案为选择 的因子 ,然后用 除以 ,那么 ,继续选择 的因子,重复操作;第二种方案为选择 的因子 ,将 除以 ,得到 。那么选择次数最少操作,将次数输出
1.2 输入格式
输入一行,包含一个数字 。
1.3 输出格式
输出一行,包含一个答案。
输入样例:
8
输出样例:
1
1.6 数据范围
在 80% 数据下:
在 100% 数据下:
赛时想法:
唯一分解定理,思路没问题,但忘开longlong了QAQ;
十年OI一场空,不开longlong见祖宗~~
解题思路:
唯一分解定理:任意一个自然数都可以分成质数之积。
判断一下是否是质数,是输出0,不是输出1;
(别忘开longlong!!!)
AC代码:
#include
#include
using namespace std;
bool prime(long long x){for(long long i=2;i*i<=x;i++){if(x%i==0){return 1;}}return 0;
}
long long n;
int main(){cin>>n;cout<
二.分组
2.1 问题描述
小可召集大家一起来玩游戏!
小可总共召集了 为玩家,每位玩家有一个专属分数 ,现在需要将 为玩家进行分组,分组之后每个组将获得一个小组专属分数 。小组专属分数为小组内每位玩家专属分数组成的集合中没有出现过的最小的自然数。比如第一组中每个人分数为 1,2 ,那么小组分数为 0 ,第二组中每个人的分数为
0,1,2 ,那么小组分数为 3 。
为了提高胜率,肯定要让
最大,请输出
最大的 。
2.2 输入格式
第一行包含一个整数n ,表示 n为玩家。
第二行输入 n个非负整数,表示ai 。
2.3 输出格式
输出一行表示最大的
2.4 输入样例
5
0 0 1 1 2
2.5 输出样例
5
2.6 提示
样例可以分成 0,1 和 0,1,2 两个小组,那么两个小组得分分别为 2 和 3
2.7 数据范围
第一个测试点有:
第二个测试点有:
第三四个测试点有:
全部测试点下:

赛时想法:
没做,无想法。
解题思路:
通标记,不考虑如何分组,只考虑一个数字贡献多少分。
0 0 1 1 2
桶标后:
2 2 1 0 1 2
所以最大分数为:2×1+2×1+1×1=5
#include
#include
#include
#include
using namespace std;
const int N=1e5+10;
int n,a;
int cnt[N];
int main() {int n;cin >> n;memset(cnt, 0, sizeof cnt);for (int i = 1; i <= n; i++) {cin >> a;cnt[a]++;}int now = cnt[0], ans = now;for (int i = 1; i <= 1000; i++) {now = min(now, cnt[i]);ans += now;}cout << ans << endl;return 0;
}
三.抢夺地盘
1.题目大意
小可在游戏中为了防止被其他玩家抢走城镇,在排兵布阵的过程中将钱数最多的城镇放在了 p 位置,然后从 1 到 p 的钱数排布是从小到大的,从 p 到 n 的钱数排布是从大到小的。这时出现了一个问题,如果某一个城镇 a 由于钱的原因比另一个城镇 b 更靠边(距离 p 位置更远),但是战斗力 a 比 b 更大,两个城镇会爆发矛盾。如果内部发生矛盾,会影响小可的整体安排。小可现在可以通过调整城镇人数的方式更改城镇的战斗力,但是为了稳定性考虑,被更改的城镇越少越好,请问小可最少调整几个城镇可以满足要求?
赛时思路
比赛中题目理解了,但我思路是有问题的,我想的是把从1~p这部分先从小到大排序,再把p到n这部分从大到小排序,和原先输入的进行对比看有几处不同,这种方法是行不通的
解题思路
线性DP,前面,后面(单层循环时间复杂度O(n)级别优化)用sum统计,最长不上升子序列时倒着存,当最长不下降子序列做
#include
using namespace std;
int n,p;
int a[100005];
int main(){cin>>n>>p;int maxn=0;for(int i=1;i<=n;i++){cin>>a[i];if(i<=p)maxn=max(maxn,a[i]);}int sum=0;int cnt=0,dp[100005];for(int i=1;i<=p;i++){if(dp[cnt]<=a[i]){dp[++cnt]=a[i];}else{int index=upper_bound(dp+1,dp+cnt+1,a[i])-dp;dp[index]=a[i];}}sum+=p-cnt;int cnt1=0,dp1[100005];if(maxn!=a[p]){a[p]=1e9;p++;}for(int i=n;i>=p;i--){if(dp1[cnt1]<=a[i]){dp1[++cnt1]=a[i];}else{int index=upper_bound(dp1+1,dp1+cnt1+1,a[i])-dp1;dp1[index]=a[i];}}sum+=(n-p+1)-cnt1;cout<
四.闯关
1.题目大意
小可、达达可以选择一次跃过最多 m 距离继续向后闯关,不需要每个关卡都闯过去。由于小可和达达是组队参加,组委会赠与了小可和达达一个闯关神器,可以让 m 距离变成 k(m<k)。开始时神器在小可的手中,小可和达达虽然分别在两个跑道,但是可以在两人距离不超过 q (k<q)时相互传递这个闯关神器。请问小可和达达都到达终点(即第 n 个关卡),最少需要使用几次闯关神器。
比赛中的思考
本来不会,思考了一会,居然!还是不会~。尝试拿部分分顺便整一下,样例是都对了,但为何爆零也是很疑惑??
解题思路
模拟,基本上模拟整个过程,先让两人能硬走就硬走 ,处理一下每个人可以跳跃的最大距离,然后用死循环让小可,或达达尽可能往后走
#include
#define INF 0x3f3f3f3f
#define ll long long
#define N 1000005
#define M 100005
using namespace std;
int n,m,k,q,a[N],b[N],f=0;
int main() {
cin>>n>>m>>k>>q;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++) cin>>b[i];
int posa = 0,posb = 0,ans = 0;
//先让两人能硬走就硬走
//处理一下每个人可以跳跃的最大距离
while(1) {
int la,lb;
la = lb = m;
if(f == 0) la = k;
else lb = k;
//让小可,或达达尽可能往后走
for(int i=posa+1; i<=n; i++) {
if(a[i] - a[posa] <= la) {
posa = i;
} else {
break;
}
}
for(int i=posb+1; i<=n; i++) {
if(b[i] - b[posb] <= lb) {
posb = i;
} else {
break;
}
}
//判断此时posa和posb能否同时到达终点如果能,直接break
if(posa >= n && posb >= n) {
break;
} else {
//如果没有看看神器在谁手里,让它回到另一个人卡住的位置
if(posb < n) {
//达达卡住了
//在a数组中找到第一个离b最远但是能够传递神器的地方
int index = lower_bound(a+1,a+n+1,b[posb]+q) - a;
if(a[index]>b[posb]+q) index--;
ans++;
f = 1;
posa = index;
} else if(posa < n) {
//小可卡住了
//在b数组中找到第一个离a最远但是能够传递神器的地方
int index = lower_bound(b+1,b+n+1,a[posa] + q) - b;
if(b[index] > a[posa]+q) index--;
ans++;
f = 0;
posb = index;
}
}
}
cout<