【Atcoder】AGC015 C-F简要题解

80 篇文章 1 订阅
32 篇文章 0 订阅

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 &lt; 2 k , 2 k ≤ B &lt; 2 k + 1 0\leq A&lt;2^k,2^k\leq B&lt;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 ′ &lt; x , v ′ &gt; v x&#x27;&lt; x,v&#x27;&gt;v x<x,v>v
  2. x ′ &gt; x , v ′ &lt; v x&#x27;&gt;x,v&#x27;&lt; v x>x,v<v
  3. x ′ &lt; x , v ′ &lt; v 且 v ′ &gt; 某 个 2 类 点 的 v x&#x27;&lt; x,v&#x27;&lt; v且v&#x27;&gt;某个2类点的v x<x,v<vv>2v
  4. x ′ &gt; x , v ′ &gt; v 且 v ′ &lt; 某 个 1 类 点 的 v x&#x27;&gt;x,v&#x27;&gt;v且v&#x27;&lt; 某个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 &lt; l ′ ≤ r ′ &lt; r l&lt;l&#x27;\leq r&#x27;&lt;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 ) &gt; 1 \gcd(x,y)&gt;1 gcd(x,y)>1 f ( x , y ) &gt; 1 f(x,y)&gt;1 f(x,y)>1的数对显然不优。所以特判最大步数为 1 1 1的情况,其余情况只需要考虑 gcd ⁡ \gcd gcd 1 1 1的数对
  • 定义数对 ( x , y ) (x,y) (x,y)是好的当且仅当不存在 x ′ &lt; x , y ′ &lt; y x&#x27;&lt;x,y&#x27;&lt;y x<x,y<y使得 f ( x ′ , y ′ ) &gt; f ( x , y ) f(x&#x27;,y&#x27;)&gt;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 &gt; F i + 2 + F i − 1 x\geq F_i,y&gt;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 &gt; F i + 2 + F i − 1 , b = p y + x ≥ y + x &gt; F i + 3 a=y&gt;F_{i+2}+F_{i-1},b=py+x\geq y+x&gt; F_{i+3} a=y>Fi+2+Fi1b=py+xy+x>Fi+3,所以存在 x ′ = F i + 2 &lt; a , y ′ = F i + 3 &lt; b x&#x27;=F_{i+2}&lt;a,y&#x27;=F_{i+3}&lt;b x=Fi+2<a,y=Fi+3<b,满足 f ( x ′ , y ′ ) = i + 2 &gt; f ( a , b ) f(x&#x27;,y&#x27;)=i+2&gt;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&#x27;,y&#x27;)=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<cstdio>
#include<algorithm>
#include<vector>
#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);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值