题解:CF2231F Quadratic Jumps
wang_freedom · · 题解
简单题,完全够不上2600和紫。
思路:
首先有个很经典东西叫四平方和定理,就是说一个正整数肯定能被拆成不超过四个完全平方数之和,答案的上界就压下来了。
考虑到还有跳出
跳过去又跳回来是有可能跳出
套一个平方差公式,变成
如此便可预处理出左右横跳两步是否会超出区间。
具体来说就是
这样我们就可以
答案为
总复杂度为
代码:
//你全家都是网珺淏
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rop(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define por(i,a,b) for(int i=a;i>b;i--)
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef long double ld;
using namespace std;
int t,n,q,dp[200005],sq[200005],x[200005],y[200005],a,b;
bool check2(int a,int b){
if(a>b)
swap(a,b);
if(dp[b-a]<=2)
return 1;
if(!x[b-a])
return 0;
if(a+y[b-a]*y[b-a]<=n||b-y[b-a]*y[b-a]>=1)
return 1;
return 0;
}
bool check3(int a,int b){
rep(x,1,447){
if(a+x*x<=n)
if(check2(a+x*x,b))
return 1;
if(a-x*x>=1)
if(check2(a-x*x,b))
return 1;
}
return 0;
}
void solve(){
cin>>n>>q;
while(q--){
cin>>a>>b;
int ans=dp[b-a];
if(check2(a,b))
ans=min(ans,2ll);
if(check3(a,b))
ans=min(ans,3ll);
cout<<ans<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
dp[0]=0;
rep(i,1,447)
sq[i*i]=i;
rep(i,1,200000)
if(!sq[i])
sq[i]=sq[i-1];
rep(i,1,200000){
dp[i]=4;
for(int j=1;j*j<=i;j++){
dp[i]=min(dp[i],dp[i-j*j]+1);
if(i%j||(i/j-j)&1)
continue;
x[i]=i/j-j>>1;
y[i]=i/j+j>>1;
}
}
while(t--)
solve();
return 0;
}
/*
?现在jc方式那么低级啊
*/