瑞士轮 题解
2023-08-30 23:25:39
发布于:广东
23阅读
0回复
0点赞
题目意思:给你两个数组w和s,要求每次第一名(a[1])和第二(a[2])、第三和第四、第五和第六、第i(i+1<=n)和i+1名比赛,如果a[i].w>a[i+1].w则a[i].s++,然后重新按照a[i].s排序,重复以上操作直到操作次数等于R为止。求此时的A[Q].id
不难想到暴力算法,先把a排序,然后顺序扫描整个a如果a[i].w>a[i+1].w则a[i].s++,然后再快排一次。
时间复杂度为O(R*(2n)log2(2n))对于本题n<=100000,R<=50的规模
运算次数为5020000018=1.8亿次,会超时。
正解,设一个数组Win存储这一轮赢了的人,Lose存储输的。
依然是顺序扫描a,把赢了的人放入Win中,输了的放入Lose中。
然后把Win和Lose按照cmp来合并,合并后的数组就是新的a,更新a,继续下一次归并排序直到次数等于R,输出答案;
这种做法由于是直接合并,扫描是O(2n)的,所以最后的时间复杂度是O(R2n)就可以过了。
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define maxn 100005
#define inf 1000000010
using namespace std;
int n,R,Q;
struct data
{
int id,s,w;
}Win[2*maxn],Lose[2*maxn],Ans[2*maxn];
bool cmp(data a,data b)
{
return a.s>b.s || (a.s==b.s && a.id<b.id);
}
void solve()
{
int ai=1,bi=1;
for(int i=1;i<=2*n;i+=2)
{
if(Ans[i].w<Ans[i+1].w)
{
Ans[i+1].s++;
Win[ai++]=Ans[i+1];
Lose[bi++]=Ans[i];
}
else
{
Ans[i].s++;
Win[ai++]=Ans[i];
Lose[bi++]=Ans[i+1];
}
}
int i=1,j=1,k=1;
while(i<ai && j<bi)
{
if(cmp(Win[i],Lose[j]))
{
Ans[k++]=Win[i];
i++;
}
else
{
Ans[k++]=Lose[j];
j++;
}
}
while(i<ai)Ans[k++]=Win[i++];
while(j<bi)Ans[k++]=Lose[j++];
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
scanf("%d%d%d",&n,&R,&Q);
for(int i=1;i<=2*n;i++)
{
scanf("%d",&Ans[i].s);
Ans[i].id=i;
}
for(int i=1;i<=2*n;i++)
scanf("%d",&Ans[i].w);
sort(Ans+1,Ans+2*n+1,cmp);
for(int i=1;i<=R;i++)
solve();
printf("%d\n",Ans[Q].id);
return 0;
}
全部评论 1
《会超时》
2024-06-17 来自 广东
0呃
2024-06-21 来自 广东
02024-06-21 来自 广东
0
有帮助,赞一个