题目一:序列查询【100分】
签到题,注意把题目读完,最后有一句提高效率的提示,不按照这个思路可能会超时,不需要开一个数组,直接读入一遍数据就过
#include<iostream>
using namespace std;
int n,m;
int main()
{
cin>>n>>m;
int ans=0;
int pre=0;
for(int i=1;i<=n;i++)
{
int t;cin>>t;
ans+=(i-1)*(t-pre);
pre=t;
}
ans+=n*(m-pre);
cout<<ans;
return 0;
}
题目二:序列查询新解【100分】
一开始没有思路,先遍历1-N暴力拿力了70分(肯定的),后面再想办法怎么改进的
- 根据第一题的思路,第一题里面,将f进行一段一段地求解,而不是一个一个地求值,就能有效地避免超时
- f(x)和g(x)都是公差为1的等差数列(只是每一项的长度特殊,f每一项的长度不一样,g每一项的长度一样),所以都具有段的性质,我们也可以仿照第一题,一段一段地进行求解,先将f(x)分段,每一段值相同,f(x)段里面再按照g(x)分段,每一段里面值相同,最后进行差值计算的最小段中f(x)和g(x)都相同,直接相减再乘以段的长度即可
AC代码:
#include<iostream>
#include<stdlib.h>
using namespace std;
int a[100005];
int n,N;
int main()
{
cin>>n>>N;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int r=N/(n+1); //相同g的最大长度
a[n+1]=N; //最后一个的取值不能随便取,要根据题目来取
long long ans=0;
for(int i=0;i<=n;i++) //按照f(x)进行分段,每一段f(x)=i
{
int num =0; //当前f段下相同g段的长度
int f=i;
for(int j=a[i];j<a[i+1];j+=num) //按照g分段,每一段的开始为j,每一段g=j/r; 每一段的长度num需要计算
{
int g=j/r;
num=(g+1)*r-j; //当前g的取值段可能有一部分在上一个f段中,不能直接等于r,g+1段的起始位置减去当前段开始位置即当前段的长度
if(num>a[i+1]-j) num =a[i+1]-j; //剩下的g段超出了f段,截断
ans+=abs(g-f)*num; //在这个最小段内,f值相同,g值相同
}
}
cout<<ans;
return 0;
}