题目描述
Whence这个学期考了 n次试,每一次都有一个0~20000之间的整数分数。Whence本来的状态应该是每一次考试都比前一次多一分(除第一次),但由于他很不稳定,偏差可能很大。对于第i次考试,如果有第j次考试满足1≤j ≤ i ≤n,且以第j次考试分数作为基准估计的第i次考试成绩比实际成绩低,就说第i次考试鄙视了第j次考试(估计分可以超过20000)。为了提高自信,Whence想知道他这个学期所有考试总共有多少次鄙视。
输入输出格式
输入格式:
第 1 行 n (1 第2行为n次考试成绩。
输出格式:
1行,这个学期所有考试的总共鄙视次数(总数可能很大,只需要输出总数mod 12345的值)。
输入输出样例
输入样例#1:
4
1 3 3 5
输出样例#1:
3
提示信息提示
样例说明:第一次考试的分数是1,那么估计应该是第二次为2,第三次为3,第四次为4,但第二次实际分数为3,比2大,这是1次鄙视;第四次实际分数为5,比估计的4大,这也是1次鄙视;第二次考试的分数是3,那么估计应该是第三次为4,第四次为5,实际分数分别是3和5,所以没有鄙视;第三次考试的分数为3,那么估计第四次是4,但实际为5,这又是1次鄙视。因此总鄙视次数为3次。
算法
1.暴力
根据题意枚举每一次的预估分数并与实际分数比较:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[50001],ans=0,b[50001];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
b[j]=a[i]+(j-i);
if(b[j]<a[j]) ans=(ans+1)%12345;
}
}cout<<ans;
return 0;
}
时间复杂度(O(n^2))
空间复杂度(O(n))
TLE
算法2
归并排序实现逆序对+数学变形:
将 代入
得
变形得
将所有a[i]提前减去i
则“a[i]<a[j]”
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]-=i;
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(a[i]<a[j])ans=(ans+1)%12345;
}
cout<<endl;
}
转化为求逆序对:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[500001],ans=0,b[500001];
void f(long long l, long long r)
{
if(l==r) return;
long long mid=(l+r)/2;
f(l,mid);
f(mid+1,r);
long long i=l,k=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(a[i]>a[j])
{
ans+=(mid-i)+1;
ans%=12345;
b[k++]=a[j++];
}
else b[k++]=a[i++];
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for( long long i=l;i<=r;i++) a[i]=b[i];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]-=i;
}
reverse(a+1,a+n+1);
f(1,n);
cout<<ans;
return 0;
}