2018的AHOI是笔者初一是打的一场比赛,但是结果很使人哀伤,无奈爆零
但是时间不许我们徘徊,我们要有希望——转眼间AHOI2019就要到了——我要一血前耻!
BB一番后现在就要开始正题了(题号不一定正确见谅)
T1:报名签到 https://www.luogu.org/problemnew/show/P4445(自己看去,懒得复制整理了)
这题很水但是我当时还是爆零
这是比较简单的一道题目,题意也是比较容易理解的,为了不发生冲突,我们就去选相邻两者中比较大的一方,这样是两全其美的,但是要注意开long long。(long貌似也可以)
下面是代码:
#include <bits/stdc++.h>
using namespace std;
long long ans;
int n;
int a[100009];
int main()
{
cin>>n; //输入
for (int i = 1; i <= n; i++)
cin>>a[i];
for (int i = 1; i < n; i++)
ans += max(a[i],a[i+1]); //计算
cout<<ans; //输出
return 0;
}
T2:根式化简 https://www.luogu.org/problemnew/show/P4446
此题本人表示不会
这题个人感觉很难,luogu里的题解都是数论搭配其他算法或是什么玄学东西的,反正我不会,我对数论一无所知呀,只能掏出自己烂的可怜的暴力了。。。思路就不说了,那么烂,肯定都懂。
代码:
#include <bits/stdc++.h>
using namespace std;
long a,x[100009],n,ans;
int judge(int z)
{
for (int i = 1; i <= (int)sqrt(z); i++)
if (i * i * i == z)
{
a = i;
return true;
}
return false;
}
int main()
{
cin>>n;
for (int i = 1; i <= n; i++)
cin>>x[i];
for (int i = 1; i <= n; i++)
{
ans = 1;
for (int b = 1; b <= (int)sqrt(x[i]); b++)
if (x[i] % b == 0 && judge(x[i]/b))
ans = max(ans,a);
cout<<ans<<endl;
}
return 0;
}
T3:分组 https://www.luogu.org/problemnew/show/P4447
这题笔者在思考了一段时间后还是有意思理解的(我看题解了,反正能搞懂就行)
刚开始的几次是60分的,思路也很简单,就是模拟贪心的思想,维护多个队列,刚开始是只有一个的,然后不停往里面塞数字(注意,是有序的!从小到大最佳)如果不符题意,就重新开一个队列,最后我们的答案也就是所有队列长度中的最小值了。
代码:
#include <bits/stdc++.h>
using namespace std;
struct node
{
long l; //长度:length
long b; //队首:beginning
long p; //实力值:power
}x[100009];
long ans = 100009,a[100009];
int n;
int main()
{
cin>>n; //输入
for (int i = 1; i <= n; i++)
cin>>a[i];
sort(a+1,a+n+1); //排序
//对第一个队列进行预处理
x[1].p = a[1];
x[1].l = 1;
x[1].b = 1;
for (int i = 2; i <= n; i++)
{
if (a[i] == x[i-1].p + 1) //判断可符题意
{
x[i].l = x[i-1].l + 1;
x[i].p = a[i];
x[i].b = x[i-1].b;
}
else //反之要重新开一个队列,进行操作
{
// cout<<'q';
ans = min(ans,x[i-1].l);
x[i].b = i;
x[i].l = 1;
x[i].p = a[i];
}
}
cout<<min(ans,x[n].l); //输出
return 0;
}
但是这样写,可否会有不足之处呢?才60分,肯定有!
我们可以再回顾一下,题面:
要求的是最少人数组的最大值?什么鬼东西mmp,理解一下,便是“使人数最少的组里面的人尽量多。”
就是是各组里面的人数尽量均衡——不是一定都要把所有能接上的值都给目前“最好的”,或者是最后一个队列,而是适当的分布,使实力值尽量均匀,每一组的人都在全局情况允许的情况下尽量最多。
来解决这个问题,我们便需要同时维护多个序列,但是按找上面那个垃圾做法,每一次维护,后半段都要发生改变的,超时不是梦想,肯定要超时呀,所以,对于每一个队列,我们都只维护一个元素,也就是队尾,因为来判断是否要相接的并不是前面的元素(前面的没鸟用),而是队尾的元素(翻身农奴把歌唱),只要用它就可以判断是否可以接上一个人。
维护多个队列的问题就解决了,但是下一个问题又来了,就是如何使每组的实力值均匀呢?如何“使得人数最少的组人数最多”呢?我们可以思考一下,每一次需要重新开队列,都是在前一个的下面的,而下面的未能接上只有2种可能:①是相等的;②太犇了;而上面的人数通常都是比下面的大的,下面的数都很“神奇”,所以我们就可以在每一次接的时候倒着来——更有可能能接上。
那下列的一组数据来说吧:
这样思路便是很清晰了,下面是代码:
#include <bits/stdc++.h>
using namespace std;
struct node
{
long l;
//long b;
long p;
}x[100009];
long ans = 100009,a[100009];
int n,num;
int main()
{
cin>>n;
for (int i = 1; i <= n; i++)
cin>>a[i];
sort(a+1,a+n+1); //排序
x[1].p = a[1]; //预处理
x[1].l = 1;
num = 1; //这个方法需要统计队列的个数,方便对多个队列进行维护
// x[1].b = 1;
for (int i = 2; i <= n; i++)
{
bool judge = true; //判断是否需要新开队列
for (int j = num; j >= 1; j--) //同上面说的,倒着来
{ //看能不能找到能接上的“最小的”
if (x[j].p == a[i] - 1)
{
x[j].p = a[i];
x[j].l++;
judge = false;
break;
}
}
if (judge) //接不上,另一种处理方式
{
num++;
x[num].l = 1;
x[num].p = a[i];
}
}
//for (int i = 1; i <= num; i++)
// cout<<x[i].p<<' '<<x[i].l<<endl;
for (int i = 1; i <= num; i++) //找“人数最少的人数最多的组”的人数
{
ans = min(ans,x[i].l);
// cout<<ans<<endl;
}
cout<<ans; //输出
return 0;
}
T4:球球的排列
这题本来想写暴搜或用STL函数来枚举的,但是鬼畜的代码怎么都调不出来。。。QWQ。。。所以直接输出了n,后面。。。就没了吧。。。
AHOI2019加油!