你有两个数组:一个是由n个0组成的数组a,一个是由n个整数组成的数组b。您可以对数组a应用以下操作任意次数:选择长度为k的a的某个子段,并将等差数列1、2、、k加到这个子段上——即将1加到子段的第一个元素上,将2加到第二个元素上,以此类推。所选子段应在数组a的边界内(即所选子段的左边界为I,则满足条件1 < <l+k-1 < n)。注意,添加的级数总是1,2,。, k,而不是k, k-1,,1或任何其他元素(即,子段的最左边的元素总是增加1,第二个元素总是增加2,以此类推)。你的任务是找到满足条件a所需的最小操作数;2 b;对于从1到n的每个i。注意,条件a b应该同时满足所有元素。输入输入的第一行包含两个整数n和k (1 < k < n < 3 -105)——分别是两个数组中的元素数量和子段的长度。输入的第二行包含n个整数b1, b2,,bn (1 <b <1012),其中b是数组b的第i个元素。输出打印一个整数-对于从1到n的每个i,满足条件a 2b所需的最小操作数。
Examples
input
Copy
3 3 5 4 6
output
Copy
5
input
Copy
6 3 1 2 3 2 2 3
output
Copy
3
input
Copy
6 3 1 2 4 1 2 3
output
Copy
3
input
Copy
7 3 50 17 81 25 42 39 96
output
Copy
92
题解:
根据贪心的思想每次我们应该找从后往前找b中第一个大于a的,并且把k数组的右边界放到这里
具体证明(不会(毕竟贪心的大部分题目是很难证明其正确性的OuO))
那么我们该怎么模拟这个过程呢,(具体代码中体现:注释)
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
using namespace std;
#define int long long
const int N = 4e5 + 10;
typedef pair<int, int> PII;
int n,k;
int b[N];
int a[N];
int add,cnt,ans;
void solve()
{
cin >> n >> k;
for(int i = 1;i <= n;i++)
{
cin >> b[i];
}
for(int i = n;i >= 1;i --)
{
add -= cnt*1;//由于往前一位代表等差数列往前移了一项,长度为k的区间进行了多少次操作(cnt),应该减去cnt*1
if(i <= n - k)
cnt -= a[i + k];//由于他是一个长度为k的滑动区间超过这个范围就不影响了,所以把不影响的部分剪掉
if(add < b[i])
{
int t = min(i,k);//区间长度不够k时取最右边的
int num = (b[i] - add + t - 1)/t;//此时需要多少操作
a[i] = num;//记录i位置进行了多少次操作
cnt += num;//长度为k的区间内进行了多少次操作
ans += num;
add += num*t;//此时此处经历操作后的大小
}
}
cout << ans;
}
//1 2 4
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t = 1;
// cin >> t;
//scanf("%lld",&t);
while (t--)
{
solve();
}
}
//1 1 1 0 1
//1 1 1 0 1
//1 1 1 0 1
//1 1 1 0 1
//0 1 1 1 1
//0 1 1 1 1