CCFCSP:202112-2:序列查询新解
题目链接:序列查询新解
思路:
整体思路:分段计算。第一题序列查询,明确暗示分段乘法运算可大幅提高算法效率。
直接计算的暴力解70分。
第一题链接:序列查询
先以f(i)取值相同的区域进行划分若干段f1,f2,f3…
其中i在区间[ a[k-1] , a[k]-1 ]内时, f[i]的取值为 k-1
在f[i]取值相同的子区间内,再次划分为g[j]取值相同的若干孙子区间g1,g2,g3…
其中g[j]取值为j/r,每r个长度区间的g[j]取值相同
f[i]与g[j]按孙子区间分段相乘再相加
代码
#include<iostream>
#include<cmath>
using namespace std;
const int M = 1e5 + 10;
int a[M];
int main(){
int n, N;
scanf("%d%d", &n, &N);
for(int i = 1; i<= n; i++) scanf("%d", &a[i]);
a[0] = 0, a[n+1] = N; //边界
int len = 0;
int r = N / (n + 1);
long long error = 0;
for(int i = 1; i <= n + 1; i++){
long long sum = 0; //分段子区间和
int f = i - 1;
for(int j = a[i-1]; j <= a[i] - 1; j += len){//j从a[0]=0开始至a[n]=N结束,涵盖整个区间
//len为可变步长,步长为每个g段长度
int g = j / r;
int g_end = (g + 1) * r - 1; //取值为g[j]的最后一个下标
if(g_end > a[i]-1) g_end = a[i]-1; //是否超出本f段子区间右端点
int g_len = g_end - j + 1; //该g段子区间长度
sum += abs(f - g) * g_len;
len = g_len;
}
error += sum;
}
printf("%lld", error);
return 0;
}
若有更好的思路,欢迎补充!