假设时间限制为1秒
106游刃有余
107勉勉强强
108很悬,仅结构体非常简单的情况
POJ No.1852
对于最短的时间来说,所有的蚂蚁都朝向较近的端点走是最快的。
对于最长的时间来说,两只蚂蚁遇见后折返,如果我们无视蚂蚁与蚂蚁之间的区别,其实就相当于两只蚂蚁一直以同一个方向前进然后走到终点。所以这个时候我们就可以以所有蚂蚁中离端点最远的一个作为答案。
题目链接
int L,N;
int x[max_n];
void solve(){
int minT=0;//求最小时间,先判断当前点是往左走快还是右走快,然后从中取最大的。
for(int i=0;i<N;i++){
minT=max(minT,min(x[i],L-x[i]));
}
int maxT=0;
for(int i=0;i<N;i++){
maxT=max(maxT,max(x[i],L-x[i]));
}
cout << minT << endl << maxT << endl;
}
抽签问题
题目:
挑战程序设计竞赛page.2
O(n4)算法:
使用4层for循环嵌套,可求得答案,但将n=1000代入n4可以得到1012,直接回TLE。
算法改进:
假设原始算法采用a,b,c,d四个循环嵌套得到答案,那么最内层的循环d所作的事情就是检查是否有kd使得ka+kb+kc+kd=m,我们可以将式子移动一下,即检查是否有kd=m-ka-kb-kc,这样我们就可以检查数组中是否含有kd来减少最内层的循环。但是我们如何去判断kd在数组中呢?如果使用最朴素的做法就是依次遍历,可这样做了之后时间复杂度依然是O(n4)。所以我们这里采用二分的方法去寻找这个数,时间复杂度就退化为O(n3log2n)。
先将k数组进行排序,看k中央的数,如果比要查询的数字要大,那么我们查询左边,否则查询右边,直到找到了这个数。
int k[maxn],n,m;
bool binary_search(int x){
int l=0,r=n;
int mid;
while(r-l>=1){//可操作数大于1
int mid=(l+r)>>1;
if(k[mid]==x)return true;
else if(k[mid]>x)r=mid;
else l=mid+1;
}
return false;
}
void solve(){
for(int a=0;a<n;a++){
for(int b=0;b<n;b++){
for(int c=0;c<n;c++){
if(binary_search(m-k[a]-k[b]-k[c])){
cout << "Yes" << endl;
return;
}
}
}
}
cout << "No" << endl;
}
但是,将1000代入O(n3log2n),会发现这仍然不够,必须对算法进行进一步优化。刚才我们只着手了最后一个循环,接下来我们来看最后两个循环。
跟上面一个思路,检查是否有kc+kd=m-ka-kb,这种方法无法直接用二分,但是我们可以将kc+kd的每种情况保存起来并排序,然后就可以进行二分了。
int k[maxn],n,m,kk[maxn*maxn];//用于保存c*d的n^2种情况
bool binary_search(int x){
int l=0,r=n*n;
int mid;
while(r-l>=1){//可操作数大于1
int mid=(l+r)>>1;
if(kk[mid]==x)return true;
else if(kk[mid]>x)r=mid;
else l=mid+1;
}
return false;
}
void solve(){
int count_s=0;
for(int c=0;c<n;c++){
for(int d=0;d<n;d++){
kk[count_s++]=k[c]+k[d];
}
}
sort(kk,kk+count_s);
for(int a=0;a<n;a++){
for(int b=0;b<n;b++){
if(binary_search(m-k[a]-k[b])){
cout << "Yes" << endl;
return;
}
}
}
cout << "No" << endl;
}