题目链接:点我点我
题意:公式:,给出n个数,从a[1]到a[n],和m个数(b数组),然后从b数组里挑出连续的n个数(也就m-n+1中选择),按公式计算,使得f最小,
还有q次对a数组的操作(某个区间增加值,减少值),求出最小值。
题解:显然对a数组的处理非常简单,一开始确定一定值,然后update的时候,判断一下奇偶性质就可以直接加了(前一项正后一项一定是负的,可以抵消)。
然后就是b数组的处理了,一开始没处理好,一直在这边卡超时。先把b数组一项一项正负不同的加进去,然后再进行处理,得到c数组(代表b数组各种情况下的值),
然后排序二分一下。
这道题目感觉自己收获非常大,颠覆了我很多错误的想法:
1.二分函数lower_bound(c+1,c+c.size(),goal)-c中间那里加上的是数组长度而不是和sort一样是“地址”
2.upper_bound()函数是第一个大于val的位置(一直以为是小于等于val的最后一个位置,(尴尬 。。。)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 LL INF=1e18; 6 const int N=1e5+111; 7 LL a[N],b[N],c[N]; 8 9 int main(){ 10 LL n,m,q,pos,sum=0,tmp; 11 cin>>n>>m>>q; 12 for(int i=1;i<=n;i++){ 13 scanf("%lld",&a[i]); 14 i%2==1 ? sum+=a[i] : sum-=a[i]; 15 } 16 for(int i=1;i<=m;i++){ 17 scanf("%lld",&tmp); 18 if(i%2==0) tmp*=-1; 19 b[i]=b[i-1]+tmp; 20 } 21 for(int i=1;i<=m-n+1;i++){ 22 if(i%2) c[i]=(b[i-1]-b[i+n-1]); 23 else c[i]=(b[i+n-1]-b[i-1]); 24 } 25 sort(c+1,c+1+m-n+1); 26 LL ans=INF,x,y,z; 27 pos=lower_bound(c+1,c+m-n+1,-sum)-c; 28 if(pos==1) 29 ans=abs(sum+c[pos]); 30 else 31 ans=min(abs(sum+c[pos]),abs(sum+c[pos-1])); 32 printf("%lld\n",ans); 33 for(int k=1;k<=q;k++){ 34 ans=INF; 35 scanf("%lld %lld %lld",&x,&y,&z); 36 if(y==x) {y%2==1 ? sum+=z : sum-=z;} 37 else if((y-x+1)%2) {x%2==1 ? sum+=z : sum-=z;} 38 pos=lower_bound(c+1,c+m-n+1,-sum)-c; 39 if(pos==1) 40 ans=abs(sum+c[pos]); 41 else 42 ans=min(abs(sum+c[pos]),abs(sum+c[pos-1])); 43 printf("%lld\n",ans); 44 } 45 return 0; 46 }
时间: 2024-10-13 08:30:57