C市现在要转移一批罪犯到D市,C市有n名罪犯,按照入狱时间有顺序,另外每个罪犯有一个罪行值,值越大罪越重。现在为了方便管理,市长决定转移入狱时间连续的c名犯人,同时要求转移犯人的罪行值之和不超过t,问有多少种选择的方式? 题目链接见罪犯转移。
输入描述:
第一行数据三个整数:n,t,c(1≤n≤2e5,0≤t≤1e9,1≤c≤n),第二行按入狱时间给出每个犯人的罪行值ai(0≤ai≤1e9)
输出描述:
一行输出答案。
输入例子:
3 100 2 1 2 3
输出例子:
2初步看到题目时想到这是滑动窗口的题目,写两个for循环即可。核心代码如下:
for(int i = 0;i<=v.size()-c;++i)
{
int sum = 0;
for(int j = 1;j<=c;++j)
sum += v[i+j-1];
if(sum<=t)
++cnt;
}
但是这样做产生的问题是“运行超时”,后面一想也是,n的范围是[1,2e5],两层循环超时也在情理之中。
其实这题可以用动态规划的思想解决,首先计算前c个罪行值之和,然后每移动一个单位,则减去第一个元素,再加上新增加的元素,中间的元素都复用了。这样的话复杂度就变为线性的了。代码如下:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n,t,c,tmp;
while(cin>>n>>t>>c)
{
vector<int> v;
for(int i = 0;i<n;++i)
{
cin>>tmp;
v.push_back(tmp);
}
int cnt = 0,sum = 0;
for(int i = 0;i<c;++i)
sum += v[i];
if(sum <= t)
++cnt;
for(int i = 1;i<=v.size()-c;++i)
{
sum-=v[i-1];//减去第一个
sum+=v[i+c-1];//加上新增加的一个
if(sum<=t)
++cnt;
}
cout<<cnt<<endl;
}
return 0;
}