【Atcoder】AGC015 C-F简要题解

C.Nuske vs Phantom Thnook

把蓝点看成图上的点,相邻的蓝点看做图上的连边。
保证了是树,那么连通块数=点数-边数


*D.A or…or B Problem

妙。从位的组合角度完全没有思路。应该从集合角度考虑,最大化可以选择的连续区间:

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} 0A<2k,2kB<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)

三个集合合并后就是答案。


*E.Mr.Aoki Incubator

一个点可以染色的点共有四种:

  1. x ′ < x , v ′ > v x'< x,v'>v x<x,v>v
  2. x ′ > x , v ′ < v x'>x,v'< v x>x,v<v
  3. x ′ < x , v ′ < v 且 v ′ > 某 个 2 类 点 的 v x'< x,v'< v且v'>某个2类点的v x<x,v<vv>2v
  4. x ′ > x , v ′ > v 且 v ′ < 某 个 1 类 点 的 v x'>x,v'>v且v'< 某个1类点的v x>x,v>vv<1v

将点按速度排序,找到最小的 j j j满足 x j ≥ x i x_j\geq x_i xjxi,最大的 k k k满足 x k ≤ x i x_k\leq x_i xkxi,发现 i i i能染色的恰好就是这个连续区间 [ j , k ] [j,k] [j,k]。且任意两个点的染色区间不存在包含关系,即 l < l ′ ≤ r ′ < r l<l'\leq r'<r l<lr<r

将每个点按 r r r第一关键字, l l l第二关键字排序, f [ i ] f[i] f[i]表示前 i i i个点被染色的方案数,前缀和优化转移即可。


*F.Kenus the Ancient Greek

结论题。

欧几里得最大步数明示套斐波那契数列。设 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,xy,则 x ≥ F i , y ≥ F i + 1 x\geq F_i,y\geq F_{i+1} xFi,yFi+1

求解最优数对个数

结论:

  • gcd ⁡ ( x , y ) > 1 \gcd(x,y)>1 gcd(x,y)>1 f ( x , y ) > 1 f(x,y)>1 f(x,y)>1的数对显然不优。所以特判最大步数为 1 1 1的情况,其余情况只需要考虑 gcd ⁡ \gcd gcd 1 1 1的数对
  • 定义数对 ( x , y ) (x,y) (x,y)是好的当且仅当不存在 x ′ < x , y ′ < y x'<x,y'<y x<x,y<y使得 f ( x ′ , y ′ ) > f ( x , y ) f(x',y')>f(x,y) f(x,y)>f(x,y),定义数对 ( x , y ) (x,y) (x,y)是优秀的当且仅当: f ( x , y ) = i → x , y ≤ F i + 2 + F i − 1 f(x,y)=i\to x,y\leq F_{i+2}+F_{i-1} f(x,y)=ix,yFi+2+Fi1
  • 显然答案就是好的数对的个数。且好的数对一步之后一定会变成优秀的
    证明:对于一个数对 f ( x , y ) = i , x ≤ y f(x,y)=i,x\leq y f(x,y)=i,xy,设 x ≥ F i , y > F i + 2 + F i − 1 x\geq F_i,y>F_{i+2}+F_{i-1} xFi,y>Fi+2+Fi1。设其由一个好的数对 ( a , b ) ( a = y , b = p y + x ) (a,b)(a=y,b=py+x) (a,b)(a=y,b=py+x) f ( a , b ) = i + 1 f(a,b)=i+1 f(a,b)=i+1,其中 a = y > F i + 2 + F i − 1 , b = p y + x ≥ y + x > F i + 3 a=y>F_{i+2}+F_{i-1},b=py+x\geq y+x> F_{i+3} a=y>Fi+2+Fi1b=py+xy+x>Fi+3,所以存在 x ′ = F i + 2 < a , y ′ = F i + 3 < b x'=F_{i+2}<a,y'=F_{i+3}<b x=Fi+2<a,y=Fi+3<b,满足 f ( x ′ , y ′ ) = i + 2 > f ( a , b ) f(x',y')=i+2>f(a,b) f(x,y)=i+2>f(a,b),故 ( a , b ) (a,b) (a,b)不是好的,矛盾。

于是可以找出所有优秀的数对 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);
        }
    }
}

你可能感兴趣的:(妙,结论及推导,atcoder)