A - DDL 的恐惧
反思
现在就在ddl的恐惧之中是最值得反思的事情 。第一眼看过去觉得应该用贪心,但是还是茫然。先是用分数排序了从第一天开始做作业,然后发现在靠前的时间把靠后的作业做了虽然分多但是原本可以做完的作业被浪费了。得想个办法尽快做分多且紧迫的作业。想起了自己的种种行为比如当天做当天要交的作业……也就是说把作业放在ddl当天完成就可以了。
解题过程
用结构体表示作业,作业有分数和ddl两个属性
按照分数排序,分数优先级第一(从高到低),ddl的优先级第二(从小到大)。
用一个数组表示天数的占用状况。
排序后的作业数组从第一个开始,先占用ddl当天的时间如果被占用就向前找空闲,没有困闲便放弃该作业并记录扣掉的分。
循环完毕输出失去的分。
#include <iostream>
#include <cstdlib>
#include <cmath>
#include<algorithm>
using namespace std;
int n;
struct zy
{int ddl;
int sc;
bool operator<(const zy& p) const
{ if(sc!=p.sc)
{
return sc>p.sc;
}
else
return ddl<p.ddl;
}
}z[1020];
int main(int argc, char** argv) {
int t;
cin>>t;
for(int j=0;j<t;j++)
{ int c=0;
int dd[1020]={0};
cin>>n;
for(int i=0;i<n;i++)
{cin>>z[i].ddl;
}
for(int i=0;i<n;i++)
{cin>>z[i].sc;
}
sort(z,z+n);
int day=1,last,f=0;
last=z[n-1].ddl;//天数
int i=0;
while(i!=n)
{
if(dd[z[i].ddl]==0)//ddl当天困闲
{ dd[z[i].ddl]=1;
}
else
{
for(int u=z[i].ddl-1;u>0;u--)//寻找困闲
{
if(dd[u]==0)
{dd[u]=1;
f=1;
break;
}
}
if(f==0)
{c=c+z[i].sc;
}
}
i++;
f=0;
}
cout<<c<<endl;
c=0;
}
return 0;
}
B - 四个数列
反思
有一个小小的进步就是知道什么时候(大多数时候)直接算是会超时的了 用二分然后还想了好久二分。开了两个1600000000的数组直接报错了,虽然但是也不能胡来
解题思路
先计算出a+b和c+d的所有情况。
对c+d进行排序
从a+b的第一个开始与c+d相加,如果a+b + c+d中间的数小于0说明需要在中间之后的数中寻找,则将开始最小位置设置为中间位置+1。如果大于0说明要在之间之前寻找,将最大位置设为中间位置。(二分过程)
找到相加等于0的数后因为可能出现相同数所以继续从该位置开始向后统计直到出现不为0的情况。
#include <iostream>
#include <cstdlib>
#include <cmath>
#include<algorithm>
using namespace std;
int a[4005],b[4005],c[4005],d[4005];
int ab[16000005],cd[16000005];
int main(int argc, char** argv) {
int n,u=0,count=0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i]>>b[i]>>c[i]>>d[i];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
ab[u]=a[i]+b[j];
cd[u]=c[i]+d[j];
u++;
}
}
sort(cd,cd+u);
int m,go,end;
for(int i=0;i<u;i++)
{
go=0;
end=u-1;
while(end-go!=0)
{
m=(go+end)/2;
if(ab[i]+cd[m]<0)
go=m+1;
else
{end=m;
}
}
while( go<u )//防止相同数
{ if(ab[i]+cd[go]!=0)
break;
count++;
go++;
}
}
cout<<count;
return 0;
}
C - TT 的神秘礼物
反思
感觉很难的我是菜到无药可救了。要用两次二分直接就蒙圈了虽然讲过了。
还是要多学习……
解题过程
中位数位置可以通过公式(k+1)\2计算。
对cat数组进行排序后,ans数组的最大值为cat[n-1]-cat[0],ans数组全部为正整数(绝对值),则中位数在0~cat[n-1]-cat[0]之间。
进行二分,再二分判断是否是中位数,因为已经知道中位数的位置所以判断中位数只需判断是否在该位置。满足cat[mid2]-cat[i]>midnum的数的个数即在当前范围内的排名,通过排名可以判断这个数相对于中位数的位置,然后继续二分找数、判断…直到找到。
#include <iostream>
#include <cstdlib>
#include <cmath>
#include<algorithm>
using namespace std;
int cat[100020];
int main(int argc, char** argv) {
int n=0;
while(scanf("%d",&n)!=EOF)
{int mid,max,min;
for(int i=0;i<n;i++)
{
scanf("%d",&cat[i]);
}
sort(cat,cat+n);
max=cat[n-1]-cat[0];
min=0;
int i=0;
int midpos=(n*(n-1)/2+1)/2;//中位数位置
int ans=-1;
while(min<=max)
{
int r=0;
int midnum=(min+max)/2;
for(int i=0;i<n;i++)
{ int rank=-1;
int min2=0,max2=n-1;
while( min2<=max2)//再二分
{
int mid2=(max2+min2)/2;
if(cat[mid2]-cat[i]>midnum)
max2=mid2-1;
else
{ min2=mid2+1;
rank=mid2;
}
}
if(rank!=-1)
r=r+rank-i;
}
if(r<midpos)
min=midnum+1;
else
{
ans=midnum;
max=midnum-1;
}
}
cout<<ans<<endl;
}
return 0;
}