这题是真正意义上的折磨题,属实是给我做吐了。不过也暴露出自身的很多问题来,比如英语阅读能力不足,读了很多遍都没有读懂题,又或者是思维深度不够,没有将内存大小与题中公式结合起来。还有就是总是粗心大意,一遇到问题就用ultra compare去debug,而不是自己去思考。总是遗漏题目中的很多隐藏条件,在这题栽跟头之后,我彻底意识到算法竞赛训练是一个长期的过程,应当舍弃功利心,虚心学习,才能有所提高·。也正如刘汝佳老师所说,此题有着一定的实际意义,不仅是知识上的,也是精神上的。
原题:
简要分析:
题中主要给了两个公式:Pofs(i+1) = Pofs(i)+Sp
Qofs(i) = (Pofs+(Pofs<<A))>>B(左移运算符优先级比加号低,注意加括号)
其中,Pofs与Qofs都为偏移量,所谓偏移量,其实就是元素首地址大小,其中第0号元素首地址大小为0,也就是Pofs(0)=Qofs(0)=0.我们的任务是通过该式计算出Q存储N个元素所需最小内存K大小,。有公式K=Qofs(N-1)+Sq=(Pofs(N-1)+(Pofs(N-1)<<A))>>B+Sq. (Pofs(N-1)=Sp*(N-1))
该公式的实际意义是Q数组第N-1个元素的首地址加上Q数组单个元素存储的bit数,
同时,K>=Sq*N。
接下来,我们大致估算一下A,B的取值范围。long long是64位整数,假设极端情况N取2^20,Sp取2^10,则A,B取32也能完全遍历。
思路就已经很清晰了,枚举A,B求最小K值,K值相同时,A,B尽量小。我选择用一个结构体数组去储存算得的K以及此时的A,B。最后使用传入functor的sort对数组按题目要求排序即可。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>//memset函数
#pragma GCC optimistic(2)
using namespace std;
struct ANS
{long long ans;int A,B;
};
struct cmp
{bool operator ()(const ANS A,const ANS B) const{if(A.ans!=B.ans){return A.ans<B.ans;}else if(A.A!=B.A){return A.A<B.A;}else{return A.B<B.B;}}
};
int main(void)
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);long long N,Sp,Sq;while(cin>>N>>Sp>>Sq){ANS store[4000];memset(store,0,sizeof(store));int n=0;long long MIN=N*Sq;long long Pofs=Sp*(N-1);for(int A=0;A<=32;A++){for(int B=0;B<=32;B++){long long ans=((Pofs+(Pofs<<A))>>B)+Sq;if(ans>=MIN){store[n].ans=ans;store[n].A=A;store[n].B=B;n++;}}}sort(store,store+n,cmp());cout<<store[0].ans<<" "<<store[0].A<<" "<<store[0].B<<endl;}return 0;
}