本来打算练习贪心,在蓝桥杯训练系统里找了一道(其实安排了好几道)
果然我还是高估了自己的实力,不说了上题!
试题 算法训练 Beaver’s Calculator
资源限制
时间限制:3.0s 内存限制:256.0MB
问题描述
从万能词典来的聪明的海狸已经使我们惊讶了一次。他开发了一种新的计算器,他将此命名为"Beaver’s Calculator 1.0"。它非常特别,并且被计划使用在各种各样的科学问题中。
为了测试它,聪明的海狸邀请了n位科学家,编号从1到n。第i位科学家给这个计算器带来了 ki个计算题。第i个科学家带来的问题编号1到n,并且它们必须按照编号一个一个计算,因为对于每个问题的计算都必须依赖前一个问题的计算结果。
每个教授的每个问题都用一个数 ai, j 来描述,i(1≤i≤n)是科学家的编号,j(1≤j≤ ki )是问题的编号, ai, j 表示解决这个问题所需资源单位的数量。
这个计算器非常不凡。它一个接一个的解决问题。在一个问题解决后,并且在下一个问题被计算前,计算器分配或解放资源。
计算器中最昂贵的操作是解放资源,解放远远慢于分配。所以对计算器而言,每一个接下来的问题所需的资源不少于前一个,是非常重要的。
给你关于这些科学家所给问题的相关信息。你需要给这些问题安排一个顺序,使得“坏对”尽可能少。
所谓“坏对”,就是相邻两个问题中,后一个问题需求的资源比前一个问题少。别忘了,对于同一个科学家给出的问题,计算它们的相对顺序必须是固定的。
输入格式
第一行包含一个整数n,表示科学家的人数。接下来n行每行有5个整数,ki, ai, 1, xi, yi, mi (0 ≤ ai, 1 < mi ≤ 109, 1 ≤ xi, yi ≤ 109) ,分别表示第i个科学家的问题个数,第1个问题所需资源单位数,以及3个用来计算 ai, j 的参量。ai, j = (ai, j - 1 * xi + yi)mod mi。
输出格式
第一行输出一个整数,表示最优顺序下最少的“坏对”个数。
如果问题的总个数不超过200000,接下来输出 行,表示解决问题的最优顺序。每一行两个用空格隔开的整数,表示这个问题所需的资源单位数和提供这个问题的科学家的编号。
样例输入
2
2 1 1 1 10
2 3 1 1 10
样例输出
0
1 1
2 1
3 2
4 2
数据规模和约定
20%的数据 n = 2, 1 ≤ ki ≤ 2000;
另外30%的数据 n = 2, 1 ≤ ki ≤ 200000;
剩下50%的数据 1 ≤ n ≤ 5000, 1 ≤ ki ≤ 5000。
看了快有两个小时
得到的信息: n个科学家,每人有ki个问题,给出了每人第一个问题的资源单位数,三个参量xi、yi、mi,之后的问题所需资源单位数满足ai, j = (ai, j - 1 * xi + yi)mod mi。要求不改变对于单个科学家的问题的顺序,改变科学家之间的问题的顺序使得“坏对”最少。
思路: 不改变科学家自身问题的顺序,又要使坏对最小,设未排序前科学家自身问题的坏对数为xi。这里的坏对可以理解为一次跳跃。(重点)对于每个科学家自身的问题,每跳跃一次,就把跳跃之前的顺序数组划分为一个层次,这样就把每个科学家的问题划分为xi层。那么当把不同科学家处于同一层的问题进行绝对排序,再按层次顺序输出,就可以保证不改变科学家自身问题的顺序,并且最优顺序下的坏对数就是科学家中xi的最大值。代码实现就可以用一个结构体保存每个问题所属的科学家,所需资源单位数和层次,最后将层次相同的问题根据所需资源单位数排序,最后按层次顺序输出。
借鉴了sort函数
AC代码():
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
#define kk 200000
struct source
{
int a;//表示所属科学家
int b;//表示所需资源单位数
int c;//表示层次
}s[kk];
int cmp(source a,source b)//**该排序方法借鉴**这里非常巧妙!如果层数相等在同一层里我们就按照所需资源单位数排序,如果资源单位数相同就按照科学家编号排序,否则就按层数排序
{
if(a.c==b.c)
return a.b<b.b||(a.b==b.b&&a.a<b.a);
return a.c<b.c;
}
int main()
{
ll n,a,k,x,y,m;//n为科学家人数,a为问题资源单位数,k为问题数,xym为三个参数
int ans=0,con=0;
cin>>n;
for(int i=1;i<=n;i++)
{
int t=0;
cin>>k>>a>>x>>y>>m;
for(int j=0;j<k;j++)//获取每个科学家的信息
{
ll temp;
if(con<=kk)//题目要求范围
{
s[con].a=i;
s[con].b=a;
s[con].c=t;
con++;
}
temp=(x*a+y)%m;//计算下一个问题所需资源单位数
if(temp<a)t++;//判断是否跳跃
a=temp;
}
ans=max(ans,t);//获得最大层数。
}
cout<<ans<<endl;
if(con<=kk)
{
qsort(s,s+con,cmp);
for(int i=0;i<con;i++)
{
cout<<s[i].b<<' '<<s[i].a<<endl;
}
}
}
我什么时候才能拥有想出这个sort的人的脑回路(不然归并代码太长我懒)
😁
试题 算法训练 最大最小公倍数
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。
输入格式
输入一个正整数N。
输出格式
输出一个整数,表示你找到的最小公倍数。
样例输入
9
样例输出
504
数据规模与约定
1 <= N <= 106
这一题看着看挺简单结果wa了两发。
思路: 连续三个数存在奇偶情况,相邻的偶数求出来肯定除过二,求最大的三个互质数
仔细一想,分类讨论:
- N为奇数时就是N,N-1,N-2这三个数的乘积(相邻的两个奇数肯定互质,相邻的两个数也互质)
- N为偶数时,因为取三个数,所以情况稍微复杂一点。跳过一个最小的偶数,最小公倍数为N,N-1,N-3三个数的乘积。跳过N-2是因为N和N-2一定可以共同约掉一个2(ab/2<=a(b-1))。但是如果N可以被3整除,那么N和N-3也一定可以共同约掉一个3,这时最大互质的三个数是N-1,N-2,N-3。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll n,ans;
cin>>n;
if(n%2==0){
if(n%3==0)cout<<((n-1)*(n-2)*(n-3))<<endl;
else cout<<((n-1)*(n)*(n-3))<<endl;
}
else cout<<((n-1)*(n-2)*(n))<<endl;
}
水题还是多想想细节,不然比赛的时候白白WA在水题上还是很难受的。