题目链接:
2021年的模拟赛有一道相似的题:
对于这道题,一个不错的题解,证明的很清楚:
完整的请看该题题解区的第二条。
再加上每个周期第二个数不合法的证明:
用反证法:
需要证明的就是x-y=m时,m为偶数的情况,上面的证明可以证明4的倍数是合法的,但不能证明2的倍数不合法。
任意一个每个周期第二个数可以写成4n+2(n=0,1,2.....),假设它合法,
(2*x-m)*m=4n+2,解得:n=((2*x-m)*m)/4-2/4,很明显((2*x-m)*m)/4是个整数,减去1/2,是一个分数,与n为整数的前提矛盾。证明完毕。
省赛题目链接:
c语言网的:蓝桥杯2023年第十四届省赛真题-平方差 - C语言网 (dotcpp.com)
说明:
省赛:找到规律这道题就很简单了,但是关键时刻不要犯迷糊,我一下就算1到r有多少个减去l-1个作为结果(不能粗心啊)。实际上这个也是个前缀和?另外这个数据范围太大,用O(n)的循环一个一个判断l到r的数也会超时。
由于不一定能够想到数学上的证明方法,打表观察是一个很重要的方法,可以尝试在小数据范围里面找合法结果,观察分布,可以参考下面的视频:
[蓝桥杯]真题讲解:平方差 (打表+数学)_哔哩哔哩_bilibili
再看一下模拟赛这道题目,因为数据很小,怎么暴力枚举都能过,但是其实也能给人一些启发:
直接枚举平方差结果,而不是枚举1-2021来判断这个数是否满足条件,能减少一层循环。
循环时第二个数必须小于第一个数,否则结果为负,必须从0开始。
第一个数i的枚举范围,从1到2021是比较大的了,因为2021平方-2020平方=4080400,也就是说,2021为第一个数的 可以得到的最小的平方差已经远远超过2021了,那么比2021大的数为第一个数得到的最小平方差肯定是超过2021的,所以肯定不满足条件。
如果进一步缩小条件,可以利用平方差公式(a+b)*(a-b)=a*a-b*b,令a-b=1,平方差结果为2021,可以解得b=1010和a=1011.因此第一个数枚举到1011就可以了,再大的话得到的最小平方差肯定大于2021.
代码如下:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e3+30;
int ans = 0;
int res[N]={0};
signed main() {
cin.tie(0);
cout.tie(0);
int l,r;
cin>>l>>r;
//结论:从1开始,4个为周期,每个周期的第二个数不合法,即不存在平方差等于这个数
// for(int i=l;i<=r;i++){
// if(i%4==2) continue;
// ans++;
// }
int ll=l-1;
int t=ll/4*3+ll%4 -(ll%4>=2?1:0);
ans=r/4*3+r%4 -(r%4>=2?1:0)-t;
cout<<ans;
return 0;
}