P1309 [NOIP2011 普及组] 瑞士轮 题解
P1309 [NOIP2011 普及组] 瑞士轮
题目大意:
for ( i <=r )
让这2n个选手的成绩降序排序,第1-第2打,第3-第4打, ...... , 第2n-1和第2n打
i --i+1 打,谁能打赢?谁的实力大谁就打赢了
排序最快是2nlogn ,所以上述暴力过程,时间复杂度是:R(2nlog2n + 2n ) =2e8超时了
解释:为什么是2n ,因为有2n个人
所以,暴力代码就出来了 ,你可以先打出暴力(要学会打暴力)
cin >> n >> r >> q ;
n *= 2 ;
for ( int i = 1 ; i <=n ; i ++ )
cin >> a[ i ].s, a[ i ].id = i ;
for ( int i = 1 ; i <= n ; i ++ )
cin >> a[ i ].w ;
for( int i = 1 ; i <= r ; i ++ )
{
sort ( a +1, a+ 1 + n, cmp ) ;
for ( int j = 1 ; j <= n ; j += 2 )
{
if ( a[ j ].w > a[ j + 1 ].w ) a[ j ].s ++ ;
else a[ j + 1 ].s ++ ;
}
}
sort ( a +1, a+ 1 + n, cmp ) ;
cout << a[ q ].id ;
暴力分还比较可观, 80,超俩点
怎么优化?看时间花哪里了,----排序上,所以能不能不要每次都排序,可以的
你看,1-2 , 3-4 ,2n-1---2n,他们开打的时候是有序的
打完后,你把所有的赢家拿出来放到win[]里,你想想这些赢家是不是还是有序的,咱们本来就是有序的嘛,所有的赢家每个值都+1,那不是还是有序的
你再把所有的输家拿出来放到Lsot[]里,是不是所有的输家拿出来后也是一个有序的?
所以问题就可以变成: 把两个有序的数组合并成一个有序的数组---归并排序的并的过程---O(n),好了,时间降下来了,时间复杂度可以做到R*(2n+2n)=2e7,安全了
你能去AC吗?不要往后看,如果你实在AC出错了,你再往后看,养成独立写代码的习惯
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10 ;
struct node
{
int id , s , w ;
};
node a[ N ] ;
int n , r ,q ;
bool cmp ( node x , node y )
{
if ( x.s != y.s )
return x.s > y.s ;
return x.id < y.id ;
}
int main( )
{
cin >> n >> r >> q ;
n *= 2 ;
for ( int i = 1 ;i <=n ; i ++ ) cin >> a[ i ].s , a[ i ].id = i ;
for ( int i = 1 ; i <= n ; i ++ ) cin >> a[ i ].w ;
sort ( a +1 , a+ 1 + n , cmp ) ;
for( int i = 1 ; i <= r ; i ++ )
{ vector <node> win , lost ;
for ( int j = 1 ; j <= n ; j += 2 )
{
if ( a[ j ].w > a[ j + 1 ].w )
{
a[ j ].s ++ ;
win.push_back ( a[ j ] ) ;
lost.push_back ( a[ j + 1 ] ) ;
}
else
{
a[ j + 1 ].s ++ ;
win.push_back ( a[ j + 1 ] ) ;
lost.push_back ( a[ j ] ) ;
}
}
int k = 1 , d = 0 , x = 0 ;
while ( d <win.size ( ) && x < lost.size ( ) )
{
if ( cmp ( win[ d ] ,lost [ x ] ) )
a[ k ++ ] = win[ d ++ ] ;
else a[ k ++ ] = lost[ x ++ ] ;
}
while ( d < win.size ( ) ) a[ k ++ ] = win[ d ++ ] ;
while ( x < lost.size ( ) ) a[ k ++] = lost[ x ++ ] ;
}
cout << a[ q ].id ;
return 0 ;
}