NOIP-2018 提高组(复赛) 模拟试题之--T3思考熊的马拉松

2018 NOIP 资料下载
题面描述
今年,只思考熊参加了校园马拉松比赛。马拉松的赛道是环形的,每圈的
长度是:,完成比赛需要跑;圈。
比赛中,甲领先乙很长距离,绕过一圈或多圈后从后面追上了乙的现象叫做
“套圈” 。 套圈现象非常常见, 例如: 跑得比谁都快的熊可以套某些熊 圈;
熊经常进行日常耐力训练,套圈次数和被套圈次数基本持平;而 作为一只
老年熊,则是被套圈的那种。
与人不同的是, 思考熊在跑步时都是匀速运动。 熊是这次比赛的计时员,
他统计了参赛的只熊的速度(其中最大的一个是熊的速度) 。现
在熊希望你告诉他,当速度最快的熊到达终点时,场上所有熊中总共发生
了多少次套圈现象。
注意:在熊刚刚到达终点那一刻,如果甲恰好追上了乙,此时也算作甲将
乙套圈。
输入格式
输入的第一行包含两个整数,分别表示这个测试点的组数和这个测试点的编号。对于测试数据,保证。
每组数据的第一行包含3个正整数,分别表示思考熊的只数、跑道每圈的长度和完成比赛所需要的圈数。保证。
第二行包含个正整数表示每只思考熊的速度。保证这些数互不相同。
输出格式
输出行,分别表示每组数据中所有熊发生的套圈总次数。
样例

样例输入

1 0 3 2 6 1 2 3

样例输出

8

数据范围

所有测试点的数据规模与约定如上

题解
这是一道数学题,去隔壁请一个数竞大佬来吧。
首先我们已知比赛结束时间一定是,则此时为了求出结束时间我们就先将所有熊的速度从大到小排序,然后求即可知道能跑的最长时间。这时我们知道对于都一定有套圈的时间是,则我们可以取为答案。则因此联立方程组后可知,对于我们排序后的数列中,一定有。我们枚举每一个数即可得到答案。复杂度即为。
PS:虽然都,但是不一定满足!
贴出该题的部分分解法(50)
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
inline char get(){
static char buf[30],*p1=buf,*p2=buf;
return p1p2 && (p2=(p1=buf)+fread(buf,1,30,stdin),p1p2)?EOF:*p1++;
}
inline long long read(){
register char c=get();register long long f=1,=0;
while(c>‘9’ || c<‘0’)f=(c==’-’)?-1:1,c=get();
while(c<=‘9’ && c>=‘0’)
=(<<3)+(<<1)+(c^48),c=get();
return _f;
}
long long n,A,L;
long long v[maxn];
bool cmp(long long a,long long b){
return a>b;
}
long long ans=0;
int main(){
//freopen(“2.txt”,“r”,stdin);
long long T,C;
T=read();C=read();
//cout<<1<<endl;
while(T–){
ans=0;
n=read();A=read();L=read();
for(register long long i=1;i<=n;i++)v[i]=read();
if(n==1){
puts(“0”);
continue;
}
sort(v+1,v+1+n,cmp);
for(register long long i=1;i<=n;i++){
for(register long long j=i+1;j<=n;j++){
ans+=(L
(v[i]-v[j]))/v[1];
}
}
printf("%lld\n",ans);
}
return 0;
}

紧接着我们继续考虑更加一般的情况。

image

代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long int64;
const int MAXN = 100005;
int n;
int64 L,A;
int64 a[MAXN], b[MAXN], c[MAXN];
inline int lowbit(int x) {
return x & (-x);
}
void insert(int x) {
for (int i = x; i <= n; i += lowbit(i)) c[i]++;
}
int getsum(int x) {
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += c[i];
return res;
}
int main() {
//freopen (“running.in”,“r”,stdin);
//freopen (“running.out”,“w”,stdout);
int T, case_num;
scanf("%d%d", &T, &case_num);
while (T–) {
scanf("%d%lld%lld", &n, &A, &L);
int64 ans = 0;
int64 maxv = 0;
for (int i = 1; i <= n; i++) {
c[i] = 0;
scanf("%lld", &a[i]);
maxv = max(maxv, a[i]);
a[i] *= L;
}
sort(a + 1, a + n + 1);
reverse(a + 1, a + n + 1);
for (int i = 1; i <= n; i++) {
ans += (a[i] / maxv) * (int64) (n - 2 * i + 1);
a[i] %= maxv;
}
for (int i = 1; i <= n; i++) b[i] = a[i];
sort(b + 1, b + n + 1);
int m = int(unique(b + 1, b + n + 1) - (b + 1));
for (int i = 1; i <= n; i++) {
a[i] = int(lower_bound(b + 1, b + m + 1, a[i]) - b);
ans -= getsum(a[i] - 1);
insert(a[i]);
}
printf("%lld\n", ans);
}
return 0;
}

猜你喜欢

转载自blog.csdn.net/tianli315/article/details/84869774