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

转载来自包学长的博客  https://blog.csdn.net/howardemily/article/details/77389125

 题目的意思是就是一个数组不断的前面相加 会多产生一个数在前面但是由于这个数字是0 所以说不用管它

然后呢.......  我没有想到二分心理卧槽了一下这都想不到

接下来就是   组合的数字


就像这个这样子 其实要求的是每个数字的对于最后一个数来说 的贡献次数

由找规律吧发现这是个排列组合

代码:

//MD我就没有想到二分 果然自己二分也是很薄弱这都想不到了 
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
const int maxn=2*1e5+100;
ll a[maxn];
//可知任意某个元素的贡献次数可以用组合数来表示,然后二分判定
bool check(ll x)  
{  
    double sum=0,tmp=0;  
    for(int i=0;i<n;i++)  
    {  
        if(a[i]==0)continue;  
        ll mm=x-1,nn=mm+n-1-i;//表示C下面的那个值  
		mm = min(nn - mm,mm);  //优化啊  因为C(2,6)==C(4,6)//需要剪枝 
		tmp = a[i];  
        for(ll j=1;j<=mm;j++)  
        {  
            tmp=tmp*nn/j; 
			nn--;
            if(tmp >= k)return true;  
        }  
        sum+=tmp;  
       if(sum>=k) return true; 
    } 
	if(sum>=k) return true;   
    return false;  
}   
// 对于k=3   C(2,7)   C(2,6)   C(2,5)   C(2,4)   C(2,3) C(2,)
ll sovle()
{
	ll l=1,r=k,mid;/*这边是因为里面保证最少有一个是1所以说最多k次就可以达到了*/
	while(l<=r)
	{
		mid=(l+r)/2;
		if(check(mid))r=mid-1;	
		else l=mid+1;
	} 
	return l;
}
int main()
{
	scanf("%lld%lld",&n,&k);
	for(int i=0;i<n;i++)
	{
		scanf("%lld",&a[i]);
		if(a[i]>=k)
		{
			cout<<0<<endl;
			return 0;
		}
	}//0次  所以直接输出 然后结束 
	printf("%lld\n",sovle());
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值