把蓝点看成图上的点,相邻的蓝点看做图上的连边。
保证了是树,那么连通块数=点数-边数
妙。从位的组合角度完全没有思路。应该从集合角度考虑,最大化可以选择的连续区间:
A = B A=B A=B答案为1。
否则找到 A , B A,B A,B不同的最高位 k k k,再高的位 A , B A,B A,B相同,都看做0即可。
去掉比 k k k高的位后: 0 ≤ A < 2 k , 2 k ≤ B < 2 k + 1 0\leq A<2^k,2^k\leq B<2^{k+1} 0≤A<2k,2k≤B<2k+1
由 ( A o r B ) ≥ A , ( A o r B ) ≥ B (A\ or\ B)\geq A,(A\ or \ B)\geq B (A or B)≥A,(A or B)≥B得到:
[ A , 2 k ) [A,2^k) [A,2k)子集能或出 [ A , 2 k ) [A,2^k) [A,2k),设 B B B除 k k k位外的最高为1的位为 t t t,则 [ 2 k , B ] [2^k,B] [2k,B]子集能或出 [ 2 k , 2 k + 2 t + 1 ) [2^k,2^k+2^{t+1}) [2k,2k+2t+1),那么 [ A , 2 k ) ∪ [ 2 k , B ] [A,2^k)\cup[2^k,B] [A,2k)∪[2k,B]子集能或出 [ 2 k + A , 2 k + 1 ) [2^k+A,2^{k+1}) [2k+A,2k+1)。
三个集合合并后就是答案。
一个点可以染色的点共有四种:
将点按速度排序,找到最小的 j j j满足 x j ≥ x i x_j\geq x_i xj≥xi,最大的 k k k满足 x k ≤ x i x_k\leq x_i xk≤xi,发现 i i i能染色的恰好就是这个连续区间 [ j , k ] [j,k] [j,k]。且任意两个点的染色区间不存在包含关系,即 l < l ′ ≤ r ′ < r l<l'\leq r'<r l<l′≤r′<r。
将每个点按 r r r第一关键字, l l l第二关键字排序, f [ i ] f[i] f[i]表示前 i i i个点被染色的方案数,前缀和优化转移即可。
结论题。
欧几里得最大步数明示套斐波那契数列。设 f ( x , y ) f(x,y) f(x,y)表示数对 ( x , y ) (x,y) (x,y)的欧几里得步数。
确定最大步数
由 f ( F i , F i + 1 ) = i f(F_i,F_{i+1})=i f(Fi,Fi+1)=i得:若 f ( x , y ) = i , x ≤ y f(x,y)=i,x\leq y f(x,y)=i,x≤y,则 x ≥ F i , y ≥ F i + 1 x\geq F_i,y\geq F_{i+1} x≥Fi,y≥Fi+1。
求解最优数对个数
结论:
于是可以找出所有优秀的数对 f ( x , y ) = i f(x,y)=i f(x,y)=i推出 f ( x ′ , y ′ ) = i + 1 f(x',y')=i+1 f(x′,y′)=i+1的好的数对。
优秀的数对每层都很少:最小的是 ( F i , F i + 1 ) (F_i,F_{i+1}) (Fi,Fi+1),会产生2,3个答案,其它都只产生一个答案,总共是 log \log log级别的, 预处理出来即可。
copied by WerKeyTom_FTD
#include
#include
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pi;
const int mx=90+10,mo=1000000007;
const ll inf=1000000000000000000;
ll fib[mx];
vector<pi> a[mx];
vector<pi>::iterator it;
ll x,y,n,m,num;
int i,j,k,l,t,tot,ca,ans;
int main(){
fib[0]=fib[1]=1;
tot=1;
while (1){
fib[tot+1]=fib[tot]+fib[tot-1];
if (fib[tot+1]>inf) break;
tot++;
}
a[1].pb(mp(1,2));a[1].pb(mp(1,3));a[1].pb(mp(1,4));
fo(i,1,tot-3){
it=a[i].begin();
while (it!=a[i].end()){
x=(*it).xx;y=(*it).yy;
x+=y;
while (x<=fib[i+3]+fib[i]){
a[i+1].pb(mp(y,x));
x+=y;
}
it++;
}
}
scanf("%d",&ca);
while (ca--){
scanf("%lld%lld",&n,&m);
if (n>m) swap(n,m);
ans=1;
while (fib[ans+1]<=n&&fib[ans+2]<=m) ans++;
printf("%d ",ans);
if (ans==1){
printf("%lld\n",n*m%mo);
continue;
}
else{
num=0;
it=a[ans-1].begin();
while (it!=a[ans-1].end()){
x=(*it).xx;y=(*it).yy;
if (y<=n) (num+=(m-x)/y)%=mo;
if (y<=m) (num+=(n-x)/y)%=mo;
it++;
}
printf("%d\n",num);
}
}
}