Prefix Sums
CodeForces - 837FConsider 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
题意:
p(x)表示对于一个元素个数为m的x的序列,会产生一个序列y 为m+1个元素,且有y[i]=sum(x[j]) 0<=j<i
现在给你一个长度为n的序列A0,给你一个k,问你要至少进行几次操作,使得Ai 当中存在某一个元素的值>=k。
Ai = p(Ai-1)
每次对于第一个数组元素来说,它的前面没有,因此每次新生成的数组第一个元素都将为0,我们可以忽略掉,所以每次数组都是n个元素,其次明确 A0的每个元素都是>=0的,那么也就是说新产生的序列中最后一个元素一定是所有数中最大的.那么如果最后一个满足就一定可以了.那么我们来看看能不能快速的求出新产生的序列的最后一个值.然后观察规律
我们观察k = 2的这一行,对于最后一个元素我们发现a[0]有5个即C(1,5),a[1]有4个即C(1,4),a[2]有3个C(1,3),a[3]有2个C(1,2)
a[4]有1个C(1,1).所以对于k=2时,最后一个元素的大小就是 a[0]*C(1,5) + a[1]*C(1,4) + ……+a[4]*C(1,1),之后亦是如此
那么我们就需要求这些组合数,他们存在一些特点,C上面的数始终是k-1,而下面的数虽然变化也是有规律的,发现从i=0到i=4遍历下面的数字就是上面的k-1每次加上n-1-i,这样C的上下元素都有了就可以求组合数了。然后需要二分答案
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
ll n,k;
ll a[maxn];
bool check(ll x){
double sum = 0,tmp = 0;//sum计算最后一个数据的值,tmp计算原数组a中的每个值对sum的贡献值大小
for(int i = 0; i < n; i++){
if(a[i] == 0)
continue;
ll y = n - 1 - i;
ll mm = x - 1,nn = mm + y;//mm是C上面的数字观察可知总是比k小1,nn是下面的数字a数组有n-1个数字,nn就有
//n-1种数字,并且a数组中下标越小,nn越大
mm = min(nn - mm,mm);
tmp = a[i];
for(ll j = 1; j <= mm; j++){//算组合数
tmp = tmp * (nn - mm + j) / j;
if(tmp >= k)
return true;
}
sum += tmp;
if(sum >= k)
return true;
}
return false;
}
void solve(){//二分答案
ll l = 1,r = k,mid;//因为至少有一个1,所以最多k次完成
while(l <= r){
mid = (l + r) >> 1;
if(check(mid)){
r = mid - 1;
}
else{
l = mid + 1;
}
}
printf("%lld\n",l);
return;
}
int main(){
scanf("%lld%lld",&n,&k);
int flag = 0;
for(int i = 0; i < n; i++){
scanf("%lld",&a[i]);
if(a[i] >= k)
flag = 1;
}
if(flag)
puts("0");
else
solve();
return 0;
}