故事的开头总是极尽温柔,故事会一直温柔……💜
?你好啊,我是“ 怪& ”,是一名在校大学生哦。 🌍主页链接:怪&的个人博客主页 ??博文主更方向为:课程学习知识、作业题解、期末备考。随着专业的深入会越来越广哦…一起期待。 ??一个“不想让我曾没有做好的也成为你的遗憾”的博主。 💪很高兴与你相遇,一起加油!
一、🌳代码如下:
#include <iostream>
#include <cmath>
using namespace std;
#define num 100002
int n=0;
int N=0;
int a[num]={0};
int r=0;
int Long=0;
long long sum=0;
void input(){
cin>>n>>N;
for(int i=1;i<=n;i++){
cin>>a[i];
}
}
long long g(int x){
return x/r;
}
int main(){
input();
r=N/(n+1);
a[n+1]=N;
a[0]=0;
for(int i=1;i<=n+1;i++){
long long sum1=0;
for(int j=a[i-1];j<=a[i]-1;j=j+Long){
int NumEnd=(g(j)+1)*r-1;
if(NumEnd>a[i]-1) NumEnd=a[i]-1;
int NumLong=NumEnd-j+1;
long long f_g=abs(i-1-g(j));
sum1=sum1+f_g*NumLong;
Long=NumLong;
}
sum=sum+sum1;
}
cout<<sum<<endl;
return 0;
}
二、🌵解题思路
1、观察性质🍠
f(x)定义:序列A中小于等于x的整数里的最大的数的下标。 g(x)计算方式:r=N/(n+1) ? g(x)=x/r 可得f(x)、g(x)分布皆为公差为1的递增序列。 示例给的图很直观的表现了此规律:
2、求解步骤🍅
(1)、题目的暗示
CSP的第一、二题联系紧密,这次的第一题中已经给出了暗示:分段! 如果忘了第一题讲是什么?可以看我的这篇文章:【CCF-CSP】202112-1-序列查询100分 其中详细分析了题意、解题思路并附上了题目截图。
(2)、如何分段
🍀先对f分段:for(int i=1;i<=n+1;i++) //以f(i)为区域划分计算 在此区域内f的取值相同,值为:i-1。 🌍再对每个f值相同的区域按照g值进行分段:for(int j=a[i-1];j<=a[i]-1;j=j+Long){//此区间内有Long个g取值为g(j)的数 🔥j值改变条件为:j=j+Long,这个Long为变值,因为g取值相同的区间不完全与f取值相同的区间对齐。 所以每次都要计算此Long:Long=NumLong=NumEnd-j+1; 注:由于此特性,所以g取值的上界可能超出了此区间(按f取值相同来划分的区间)的上界 所以需要此语句:if(NumEnd>a[i]-1) NumEnd=a[i]-1;//上界超出范围,变为区间最上界 ,来将此情况的bug修复。
(3)、求和
上述操作先按f取值相同分段,再按g值相同分段,所以在最底层的段中f值与g值皆恒定,即两者的差值也恒定:以差值乘以数量即可,最后将所有区间计算量加起来即可。
3、提交结果
三、其他思路
再附上一个代码,案例能对,但是0分,数据太大爆了,有兴趣的可以看看思路。
#include <iostream>
using namespace std;
#define num 100002
int n=0;
int N=0;
int long a[num]={0};
int long r=0;
long long sum=0;
void input(){
cin>>n>>N;
for(int i=1;i<=n;i++){
cin>>a[i];
}
}
void output(){
cout<<n<<" "<<N<<endl;
a[0]=0;
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
long long g(int x){
return x/r;
}
long long GSum(long long x,long long y){
long long gsum=0;
if(g(x)==g(y)){
gsum=g(x)*(y-x+1);
}
else{
long long xTop=(x%r)*g(x);
long long yTop=(y%r+1)*g(y);
gsum=r*((g(x)+g(y)-1)/2*(g(y)-1-g(x)+1));
gsum=gsum-xTop+yTop;
}
return gsum;
}
int main(){
input();
r=N/(n+1);
a[n+1]=N;
for(int i=1;i<=n+1;i++){
long long fFlag=i-1;
long long LeftFlag=a[i-1];
long long RightFlag=a[i]-1;
long long LongFlag=RightFlag-LeftFlag+1;
if(LongFlag==1){
long long m1=fFlag-g(LeftFlag);
if(m1<0) m1=(-1)*m1;
sum=sum+m1;
}
else if(g(LeftFlag)>=fFlag){
sum=sum+GSum(LeftFlag,RightFlag)-fFlag*LongFlag;
}
else if(g(RightFlag)<=fFlag){
sum=sum+fFlag*LongFlag-GSum(LeftFlag,RightFlag);
}
else{
int WhereFlag=0;
for(int j=LeftFlag;j<=RightFlag;j++){
if(g(j)>fFlag){
WhereFlag=j;
break;
}
}
long long LeftLong=WhereFlag-LeftFlag;
long long RightLong=RightFlag-WhereFlag+1;
long long sum1=fFlag*LeftLong-GSum(LeftFlag,WhereFlag-1);
long long sum2= GSum(WhereFlag,RightFlag)-fFlag*RightLong;
sum=sum+sum1+sum2;
}
}
cout<<sum<<endl;
return 0;
}
四、题目如下:
|