[CodeVS 1217]借教室
很容易想到线段树水过。
很可惜,这样估计也就70分。
然后这个问题是符合单调性的……可以二分答案哒。不过怎么判定?
不知道诸位还记得差分序列?记得就好,用差分序列的方法维护即可。
等等,我怎么感觉你这个做法是[tex]O(nlogn)[/tex]的,能过?
推荐一个行之有效的优化:注意一下每一次修改都是在之前的基础上反悔或前进几次,所以就可以直接在原基础上修改差分序列辣~这样效率是很高滴~
代码:
#include <cstdio> const int maxn=1e6+5; typedef long long ll; ll A[maxn]; int l[maxn],r[maxn]; ll d[maxn]; ll C[maxn]; int n,m,last=0; bool Check(int x){ register int i,cnt=0; if(x>last) for(i=last+1;i<=x;i++){ C[l[i]]+=d[i]; C[r[i]+1]-=d[i]; } if(x<last) for(i=x+1;i<=last;i++){ C[l[i]]-=d[i]; C[r[i]+1]+=d[i]; } last=x; for(i=1;i<=n;i++){ cnt+=C[i]; if(cnt>A[i]) return false; } return true; } int main(){ register int i,L,M,R; scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%lld",&A[i]); } for(i=1;i<=m;i++){ scanf("%lld%d%d",&d[i],&l[i],&r[i]); } L=1; R=m+1; while(L<R){ M=L+(R-L)/2; if(Check(M)){ L=M+1; }else{ R=M; } } if(L==m+1) puts("0"); else printf("-1\n%d\n",L); return 0; }
[BZOJ3043]IncDec Sequence
这题并不很好下手,但注意差分序列的前缀和为原值这个性质。
由此可见,所求数列的差分序列除了第一项以外都应该是0,求出满足条件的最小操作次数就轻松多了。
求满足条件的数列个数似乎也不是难事。通过差分序列易推数列第一项差分值的范围,突破口就在于此。
看起来,满足条件数列个数为[tex]max(S1,S2)-min(S1,S2)[/tex](S1,S2分别为正、负差分绝对值的和)。但是请注意,存在第一项没被操作的特殊情况。并且精度也是个问题!
/************************************************************** Problem: 3043 User: danihao123 Language: C++ Result: Accepted Time:292 ms Memory:820 kb ****************************************************************/ #include <cstdio> #include <algorithm> using namespace std; int main(){ int n; long long last=0,temp; register long long S1=0,S2=0,i,cf,ans2; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%llu",&temp); cf=temp-last; if(i!=1){ if(cf>0) S1+=cf; else S2-=cf; } last=temp; } ans2=max(S1,S2)-min(S1,S2)+1; printf("%llu\n%llu\n",max(S1,S2),ans2); return 0; }