P1956 Sum_NOI导刊2009提高(5)

题目描述

给出一个数列a1,a2,...ana_1,a_2,...a_na1,a2,...ank,pk,pk,p

Si,j=ai+ai+1+...+ajS_{i,j}=a_i+a_{i+1}+...+a_jSi,j=ai+ai+1+...+aj

Answer=min(Si,jmod  p∣Si,jmod  p>=k)Answer=min(S_{i,j}\mod p|S_{i,j}\mod p>=k)Answer=min(Si,jmodpSi,jmodp>=k)

其中i<=ji<=ji<=j,min(Si,jmod  p∣Si,jmod  p>=k)min(S_{i,j}\mod p|S_{i,j}\mod p>=k)min(Si,jmodpSi,jmodp>=k)非空。

输入格式

第一行一个正整数n,k,p

第二行n个整数,表示一个一个数列a1,a2,...an

输出格式

在第一行输出answer

输入输出样例

输入 #1
7 2 17
12
13
15
11
16
26
11
输出 #1
2

说明/提示

【数据范围】

在100%的数据中,1<=n<=100000,1<=k,p,ai<=10^8,i=1,2,...n

思路

将数列求得模意义下的前缀和s[0,1...,n], 按套路枚举s[j] (0<=j<i) 满足 (s[i]-s[j]+p)%p>=k。

分情况, 若存在s[j]使得s[i]-s[j]>=k,则s[j]<=s[i]-k且0<=s[i]-k;

若存在s[j]使得s[i]-s[j]<0但s[i]-s[j]+p>=k,则s[j]<=s[i]-k+p

(注意,上述两种情况不一定包含所有s[j])

将s[0,1,...,i-1]插入平衡树,每次分类查找然后更新答案。应该没有问题吧。

代码

#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=100010;

int s[N];
int n,k,p;

set<int> d;

int main () {
	d.insert(0);
	int ans=1e9;
	scanf("%d%d%d",&n,&k,&p);
	for(int i=1; i<=n; i++) {
		scanf("%d",&s[i]);
		s[i]=(s[i-1]+s[i])%p;
		if(s[i]>=k) {
			int h=*--d.upper_bound(s[i]-k);
			ans=min(ans,s[i]-h);
		}
		int h=*--d.upper_bound(s[i]+p-k);
		ans=min(ans,s[i]-h+p);
		d.insert(s[i]);
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/mysh/p/11815799.html