bzoj 4725 [POI2017]Reprezentacje ró?nicowe
如果只要求做出来这个题的话还是非常简单的。
直接用题目中所给的性质暴力logw级别的数列然后二分就行了,非常傻逼。
证明:不存在$f[b]-f[a]==f[r]-f[l] (b>a,r>l)$
首先不妨设$b>r,a>l$
1>当b为奇数时
$f[b]-f[a]>=f[b-1],f[r]-f[l]<f[b-1]$故不成立。
2>当b为偶数时
(1)$a==b-1$
根据定义$f[b]f-[a]$是之前未出现过的。
(2)$a<b-1$
显然若$r<b-1$则一定不成立(差一定小于f[b-2])。
当$r==b-1$时
$f[b]-f[a]==f[b-1]-f[l]$ --> $f[b-1]==f[a]-f[l]$但显然$f[b-1]>f[a]-f[l]$
所以每个数都由唯一一对$(r,l)$来表示。
显然当$f[x]>1e9$时乘2的操作就没有影响了,所以之可能是偶数项和前一项的差,直接二分算出第几个即可。
#include <bits/stdc++.h> #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) #define for1(a,b,i) for(int i=a;i<=b;++i) #define FOR2(a,b,i) for(int i=a;i>=b;--i) using namespace std; typedef long long ll; inline int read() { int f=1,sum=0; char x=getchar(); for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1; for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0'; return f*sum; } #define N 58 #define M 105 ll f[M]; bool vis[M*M]; int dui[M*M]; map <ll,pair<int,int> > st; int main () { //freopen("a.in","r",stdin); f[1]=1,f[2]=2,f[3]=4,f[4]=8; for1(5,N,i) { if(i&1) f[i]=f[i-1]*2; else { int head=1; for1(1,i-1,j) for1(1,j-1,k) { if(f[j]-f[k]<=i*i) vis[f[j]-f[k]]=1; while (vis[head]) ++head; } f[i]=f[i-1]+head; for1(1,i-1,j) for1(1,j-1,k) if(f[j]-f[k]<=i*i) vis[f[j]-f[k]]=0; } } for1(1,N,i) for1(1,i-1,j) { st[f[i]-f[j]]=make_pair(i,j); if(f[i]-f[j]<=1e9) dui[++dui[0]]=f[i]-f[j]; } sort(dui+1,dui+dui[0]+1); int n=read(); while (n--) { int x=read(); if(st.count(x)) { pair<int,int> t=st[x]; printf("%d %d\n",t.first,t.second); } else { int l=1,r=dui[0],mid,ans=0; while (l<=r) { mid=l+r>>1; if(dui[mid]<x) l=mid+1,ans=mid; else r=mid-1; } //cout<<ans<<endl; printf("%d %d\n",N+2*(x-ans),N+2*(x-ans)-1); } } }