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),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
}
}
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;
}