Watering an Array

Codeforces Round 917 (Div. 2)
C. Watering an Array
题目链接

题意:

给定n,k,d

给n个数的数组a,第i个是 a i a_i ai

给k个数的数组v,第i个是 v i v_i vi

定义两个操作,

  1. a数组中每个 a i = i a_i=i ai=i 的给答案贡献1,a数组清零
  2. 如果现在是第x天,a数组中下标 1 ∼ v [ ( x − 1 ) % k + 1 ] 1\sim v[(x-1)\%k+1] 1v[(x1)%k+1] 的位置都加1

每天必须且只能进行其中一个操作,问d天后最多能得多少分

思路:

好题,不过有点难。

发现操作1进行后a数组就会被清空,加上d相当大,所以感觉应该可以可以分为两部分,第一部分就是第1天从带初值的a到某天第一次清空a数组这一段,第二部分就是后面开始对一个固定的操作序列进行循环。不过操作序列v的值是不确定的,所以猜测循环的操作序列可能和v的值没有关系。

再研究研究发现,因为第二个操作是给1~vi下标位置的a增加1,所以,a数列是单调不增的,ai==i的要求是单调递增的,也就是说,不管搞几次操作2,最多只会产生一次贡献,那么不如进行完一次第二次操作就进行第一次操作,然后循环就行了。

这样我们就只需要去算前一部分就行了,发现通过前面说的循环操作只要两天就至少可以拿到1分,那么第一部分就一定不可能超过2*n天,否则光保底就有n分多了,而你第一部分最后一次收割,n个位置最多拿到n分,这样就不划算了。

一看数据范围,n=2000,第一部分直接暴力就行了

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
 
int T,n,k,d;
int a[maxn],v[maxn];
 
int main(){
	cin>>T;
	while(T--){
		cin>>n>>k>>d;
		for(int i=0;i<n;i++)
			cin>>a[i];
		for(int i=0;i<k;i++)
			cin>>v[i];
		
		ll ans=0,cnt;
		for(int i=0;i<=min(d-1,2*n);i++){
			cnt=0;
			for(int j=0;j<n;j++)cnt+=(a[j]==j+1);
			ans=max(ans,cnt+(d-i-1)/2);
			for(int j=0;j<v[i%k];j++)
				a[j]++;
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值