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; }