[SNOI2020]取石子(数学+打表找规律)

挺有意思的一道题

容易发现k越大甲越容易赢,那么a[i]表示最小的可以使甲赢的数,则a[i-a[i]]>=2a[i],可以打表,然后发现这个表与斐波那契数列有关。

众所周知,任何自然数都可以被唯一拆分成若干不同斐波那契数的和,即可以化为斐波那契进制,然后最小的斐波那契数(即斐波那契进制下的lowbit)即为a[i]

然后a数组即k本质上不同的数只有至多90个(斐波那契数在1e18以内的个数),然后s[i][j]表示前fib[i]项中fib[j]出现次数,这个很容易做出来。

然后询问答案难度就不大了……

#include<bits/stdc++.h>
using namespace std;
int p,T;
long long n,k,ans,f[100],s[100][100];
int main()
{
    f[0]=1,f[1]=1;
    for(int i=1;i<=90;i++)
    {
        f[i+1]=f[i]+f[i-1],s[i][i]=1;
        for(int j=1;j<=i;j++)s[i+1][j]=s[i-1][j]+s[i][j]-(j==i-1);
    }
    for(int i=1;i<=90;i++)for(int j=1;j<=90;j++)s[i][j]+=s[i][j-1];
    scanf("%d",&T);
    while(T--)
    {
        ans=p=0;
        scanf("%lld%lld",&k,&n);
        while(f[p+1]<=k)p++;
        for(int i=90;i;i--)if(n>f[i])n-=f[i],ans+=s[i][p];
        printf("%lld\n",ans);
    }
}

 

posted @ 2020-09-06 17:25  hfctf0210  阅读(228)  评论(0编辑  收藏  举报