1. 程式人生 > 實用技巧 >[SNOI2020]取石子(數學+打表找規律)

[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); } }