Consider the function p(x), where x is an array of m integers, which returns an array y consisting of m + 1 integers such that yi is equal to the sum of first i elements of array x (0 ≤ i ≤ m).
You have an infinite sequence of arrays A0, A1, A2..., where A0 is given in the input, and for each i ≥ 1 Ai = p(Ai - 1). Also you have a positive integer k. You have to find minimum possible i such that Ai contains a number which is larger or equal than k.
Input
The first line contains two integers n and k (2 ≤ n ≤ 200000, 1 ≤ k ≤ 1018). n is the size of array A0.
The second line contains n integers A00, A01... A0n - 1 — the elements of A0 (0 ≤ A0i ≤ 109). At least two elements of A0 are positive.
OutputPrint the minimum i such that Ai contains a number which is larger or equal than k.
Examples2 2 1 1
1
3 6 1 1 1
2
3 1 1 0 1
0
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn=2e5+10;
ll val[maxn];
int n;ll k;
/*
不得不说帅爷就是强啊,这分析能力也太牛了
我看到的第一反应也是二分,但是看到2e5之后我就放弃了
有种什么感觉呢,就在门口,可是我们就放弃了的感觉
感觉有点可惜吧,这个题是属于我们能力范围内的,不是超出所学的范围
这就很难受
我没想到前缀和增长的这么快 ,4个1的话,1000次就可以到达1e18,
这也告诉我们brute force有时候真的很有用,我是真的没敢想暴力,但是一分析
确实复杂度是可以承受的,但是二分的时候还有一个问题就是check()函数,如果我们
直接乘的话,就会直接爆掉,只能用除法,这样的话,可以控制在long long 以内。
还有一点,就是1 0000 1,和1 1111 1是等价的,因为一次之后就是后面的了,没有
这点我感觉还是做不出来的
*/
ll get_two(ll a,ll b){
ll ans=(k-b)/a;
if((k-b)%a) ans++;
return ans;
}
int check(ll x,ll a,ll b,ll c){
ll tmp=(x+1)*a+2*b,tt=2*(k-c)/x;
if((2*(k-c))%x) tt++;
if(tmp>=tt) return 1;
return 0;
}
ll get_thr(ll a,ll b,ll c){
ll l=1,r=2e9,mid;
while(l<=r){
mid=(l+r)>>1;
if(check(mid,a,b,c)){
r=mid-1;
}
else
l=mid+1;
}
return r+1;
}
int main(){
scanf("%d %lld",&n,&k);
int num0=0,yes=0,fl=0;
for(int i=1;i<=n;i++){
scanf("%lld",&val[i]);
if(val[i]!=0&&fl==0) fl=i;
if(val[i]>=k) yes=1;
}
if(yes){
printf("0\n");
return 0;
}
ll ans;
if(fl==n-1){
ans=get_two(val[n-1],val[n]);
}
else if(fl==n-2){
ll a=val[n-2],b=val[n-1],c=val[n];
ll ans1=get_two(a,b);
ll ans2=get_thr(a,b,c);
ans=min(ans1,ans2);
}
else{
ll cnt=0;
int flag=0;
while(!flag){
cnt++;
for(int i=fl;i<=n;i++){
val[i]+=val[i-1];
if(val[i]>=k){
flag=1;break;
}
}
}
ans=cnt;
}
printf("%lld\n",ans);
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn=2e5+10;
ll val[maxn];
ll K;
int n;
/*
利用组合数学,将最后一个数字拆开来看
只需要看最后一个数字,因为最后一个肯定保留着总和
1 0 0 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
说明第一个数字在后面的出现次数
注意中间的剪枝,因为都是非负数,所以可以大于直接推出就好了
但是他会爆longlong,就很难受,如果用double的话,尽管精度会损失
但是他肯定是比原先的小了,只要他大于,那么原来的树一定就会
大于,这个地方比较坑
*/
int check(ll mid,int fl){
double ans=0,tmp,pre;//它竟然用double,很难受啊
mid--;
for(int i=fl;i<=n;i++){
if(val[i]==0) continue;
ll nn=mid+n-i;
ll mm=min(mid,nn-mid);
tmp=val[i];
for(ll j=1;j<=mm;j++){
tmp=tmp*(nn-mm+j)/j;
if(tmp>=K) return 1;
}
ans=ans+tmp;
if(ans>=K) return 1;
}
return 0;
}
void solve(int fl){
ll l=1,r=K,mid,ans;
while(l<=r){
mid=(l+r)>>1;
if(check(mid,fl)){
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%lld\n",ans);
}
int main(){
scanf("%d %lld",&n,&K);
int flag=0,fl=0;
for(int i=1;i<=n;i++){
scanf("%lld",&val[i]);
if(val[i]!=0&&fl==0) fl=i;
if(val[i]>=K) flag=1;
}
if(flag)
puts("0");
else
solve(fl);
return 0;
}