一、题目
二、题解
70分
被删掉找不到了XD
思路就是暴力求每个f(i)和g(i),做差取绝对值求和。
当时参加考试的我甚至连暴力的方法都没想到,太菜了哈哈哈
100分
#include<bits/stdc++.h>
using namespace std;
const int M = 100010;
int n,N;
int a[M];
int main()
{
//freopen("C:/Users/Anderson/Desktop/in.txt","r",stdin);
cin>>n>>N;
for(int i=1; i<=n; i++){
cin>>a[i];
}
a[n+1] = N;
a[0] = 0;
int r = N/(n+1);
long long sum = 0;
int cnt_g = 0;
int temp_r = r;
for(int i=0; i<=n; i++){
int f,g;
int len_f = a[i+1] - a[i];
if(len_f<temp_r){
f = i*len_f;
g = cnt_g*len_f;
temp_r = temp_r-len_f;
sum+=abs(g-f);
}
else{
while(len_f){
if(len_f>=temp_r){
f = i*temp_r;
g = cnt_g*temp_r;
len_f-=temp_r;
temp_r = r;
cnt_g++;
sum+=abs(g-f);
}
else{
f = i*len_f;
g = cnt_g*len_f;
temp_r-=len_f;
len_f = 0;
sum+=abs(g-f);
}
}
}
}
cout<<sum;
}
其实冷静一下,这道题很好做,甚至用不上什么算法。
题目中对于70%的数据1<=n<=200;n<N<=1000
那么暴力遍历1到N并循环求f是1到n,时间最多也就2e5,完全没问题。但对于后30%的数据采用暴力时间对多到了1e14,肯定是超了。
那要怎么优化呢?其实第一题就给了我们提示,只需要按照第一题的思路,将挨个求f,g变成求部分sum之后再相减即可,这样我们只需要循环从1到n而非N。过程中需要注意的是怎样去分段,不能因为我们是从1到n循环,所以直接按照数组两两相邻的子区间分段。因为很有可能f的值在这个区间既有大于g的,也有小于g的,导致结果错误。
所以过程中我们还要按照r的值再进行分段,每计算了r个值,就需要更新g的值。经过这样的分段,每段中g的值和f的值都一定是不变的,再求g和f的sum时就一定不会出现上面提到的情况了。
不过还有一个问题就是复杂度,因为还要根据r分段,所以一共是有两次循环的,有没有可能超时呢?其实做的时候我并没有仔细分析这个问题,只是感觉时间变少了,所以尝试了一下。不过仔细分析,结果也是明了的。n的范围1–1e5。最外层循环从1–n,而内层循环最复杂的情况也就是N/r也就是n+1。时间复杂度就是 O ( n 2 ) O(n^2) O(n2)。根据n的范围,最多也就1s,刚好符合条件,况且实际数据肯定复杂度更小。还遇到一个问题就是sum的值可能很大,类型应该是long long,不过出题人也很贴心,最后给了提示。