F. Prefix Sums CodeForces - 837F

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.

Output

Print the minimum i such that Ai contains a number which is larger or equal than k.

Examples
Input
2 2
1 1
Output
1
Input
3 6
1 1 1
Output
2
Input
3 1
1 0 1
Output
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;
}	


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值