P1956 Sum_NOI导刊2009提高(5)
题目描述
给出一个数列a1,a2,...ana_1,a_2,...a_na1,a2,...an和k,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,jmodp∣Si,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,jmodp∣Si,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;
}

浙公网安备 33010602011771号