CF837F
jucason_xu · · 题解
主题和生成函数相关,但是最后也附上了不用生成函数的做法。
和本题主流的矩阵快速幂无关。
首先,我们发现这道题目“序列会增长”的情况完全就是唬人的,因为我们把
我们还发现,除了序列
然后,我们考虑二分答案,每次检测进行
首先考虑的是生成函数和卷积,因为如果我们构造生成函数 check,所以总复杂度还要多一个 complex 误差不是 FFT 配 __int128 所能承受的)
我们先把序列所有的前导
对于
常见的思路是
首先,直接暴力做卷积是可以做的,但是这就显得很怨种。我们都已经推到 __int128 了,误差还是有点可怕)。
我们考虑看看
考虑求出这个东西,
然后我们的
接下来,我们发现 __int128 暴力维护上面的乘积。一旦这个积的大小超过了
一些闲话:不会生成函数怎么推最后的组合数式子?
我们可以只看第
我们发现,如果我们把 1 1 1 1 1 1 1... 这样的无穷序列排下来,求
如果我们把这个表列出来:
1 | 1 1 1 1 1
2 | 1 2 3 4 5
3 | 1 3 6 10 15
4 | 1 4 10 20 35
如此列下来,你会发现,它就是旋转
那么,我们进行坐标变换,容易发现第
#define rp(i,n) for(ll i=1;i<=n;i++)
#define rep(i,a,b) for(ll i=a;i<=b;i++)
ll n,k,a[200005];
__int128 A[200005];
inline __int128 C(ll n,ll m){
__int128 res=1,f=1;
rp(i,m)f*=i;
rep(i,n-m+1,n){
res*=i;
if(res>=f*k)return k;
}
return res/f;
}
inline void solve1(){
ll mx=0;
rp(i,n)A[i]=a[i];
int cur=0;
while(A[n]<k){
rp(i,n)A[i]=A[i-1]+A[i];
cur++;
}
cout<<cur<<endl;
}
inline bool check(ll f){
__int128 ans=0;
if(f>=k)return 1;
rp(i,n){
ll x=f,y=n-i+1;
__int128 dd=C(x+y-2,y-1);
if(a[i]&&dd>=k)return 1;
ans+=a[i]*dd;
if(ans>=k)return 1;
}
return ans>=k;
}
inline void solve2(){
ll l=1,r=1e18,mid,ans=0;
while(l<=r){
mid=l+r>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>k;
rp(i,n)cin>>a[i];
rp(i,n)if(a[i]>=k){
cout<<0<<endl;
return 0;
}
int be=1;
while(!a[be])be++;be--;
rp(i,n-be)a[i]=a[i+be];n-=be;
if(n>10)solve1();
else solve2();
return 0;
}
//Crayan_r