题解 P3034 【[USACO11DEC]牛摄影Cow Photography】
我又来发第一个题解辣~【以下代码省略头文件】
本题要考虑相对位置而不是绝对位置。。。其实很容易想到:如果5张照片中有大于或等于3张照片里牛A在牛B的前面,那么开始序列中牛A一定在牛B之前。这样我们就很容易得到了下面的代码:
int n;
int p,ans[20005];
map<int,int>r[10];
bool cmp(int x,int y)
{
int f=0;
for(int i=1;i<=5;i++)
{
if(r[i][x]<r[i][y])f++;
}
return f>=3;
}
int main()
{
cin>>n;
for(int k=1;k<=5;k++)
{
for(int i=1;i<=n;i++)
{
cin>>p;
ans[i]=p;
r[k][p]=i;
}
}
sort(ans+1,ans+n+1,cmp);
for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
return 0;
}
这个代码在USACO官网提交是AC的,USACO标程也差不多这样,但是在洛谷上只能拿80分,TLE后两个大数据,这是为什么呢?我也在这里卡了很久,不知其为啥TLE。(插叙:于是我傻逼的与kkk争论了起来,kkk说是STL-sort常数大,说改成手写版就AC了~这是有道理的,但是我有更好的办法,只需改一点点2333,最终还比kkk总共快500ms左右,想知道的继续看下去!)其实这段代码本身就是超时的,USACO开了O2所以能过。你可能会说这程序sort是nlogn,所以复杂度就是O(nlogn),可以过啊~但是别忘了map是很慢的,map速度是logn,其中n是节点个数。我们可以精确计算下上面代码的时间复杂度:5*nlogn*2*logn=10*n*(logn)^2,n取200000,所以算一下就知道大约是578000000,这还只是算了sort的cmp函数里的复杂度啊就早爆了!所以立马就得到用map不行,那么秒想到用哈希啊!(注意要解决哈希冲突)很容易得到了以下代码:
int n;
int p,ans[20005];
vector<pair<int,int> >r[10][9975];
bool cmp(int x,int y)
{
int f=0;
for(int i=1;i<=5;i++)
{
int num1=0,num2=0;
int kkk1=x%9973,kkk2=y%9973;
for(int j=0;j<r[i][kkk1].size();j++)
{
if(r[i][kkk1][j].first==x)num1=r[i][kkk1][j].second;
}
for(int j=0;j<r[i][kkk2].size();j++)
{
if(r[i][kkk2][j].first==y)num2=r[i][kkk2][j].second;
}
if(num1<num2)f++;
}
return f>=3;
}
int main()
{
cin>>n;
for(int k=1;k<=5;k++)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&p);
ans[i]=p;
r[k][p%9973].push_back(make_pair(p,i));
}
}
sort(ans+1,ans+n+1,cmp);
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}
虽然长了一些,但相比kkk的方法修改幅度小很多。我们再算下时间复杂度:忽略常数是5*nlogn,n取200000,算出来得:17000000,显然之虽然仅是STL-sort的cmp函数内时间复杂度,但是就算加上其他的复杂度也不会有问题嘚~所以这题就轻松搞定啦!23333 这也告诉我们C++党:不能依赖STL,特别是map之类狂慢的。。。也一定要算算时间复杂度,不能盲目地觉得AC就提交了~