1 solutions
-
0
最暴力解法,25pts
枚举每个可能的,然后依次计算每个,得到最小值
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=200010; int n,m; LL S; int w[N],v[N]; int l[N],r[N]; int main() { cin>>n>>m>>S; int maxv=0; for(int i=1;i<=n;i++) { cin>>w[i]>>v[i]; maxv=max(maxv,w[i]); } for(int i=1;i<=m;i++) { cin>>l[i]>>r[i]; } LL res=1e12; for(int i=1;i<=maxv;i++) { LL ysum=0; for(int j=1;j<=m;j++) { LL cnt=0,sum=0; for(int k=l[j];k<=r[j];k++) { if(w[k]>=i) { cnt++,sum+=v[k]; } } ysum+=cnt*sum; } res=min(res,abs(ysum-S)); } cout<<res; return 0; }
前缀和优化(MN),60pts
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=200010; int n,m; LL S; int w[N],v[N]; int l[N],r[N]; int cnt[N]; LL sum[N]; LL get(int W) //获取选取W的检验值 { for(int i=1;i<=n;i++) { if(w[i]>=W) { sum[i]=sum[i-1]+v[i]; cnt[i]=cnt[i-1]+1; } else { sum[i]=sum[i-1]; cnt[i]=cnt[i-1]; } } LL res=0; for(int i=1;i<=m;i++) { res=res+(cnt[r[i]]-cnt[l[i]-1])*(sum[r[i]]-sum[l[i]-1]); } return res; } int main() { cin>>n>>m>>S; int maxv=0; for(int i=1;i<=n;i++) { cin>>w[i]>>v[i]; maxv=max(maxv,w[i]); } for(int i=1;i<=m;i++) { cin>>l[i]>>r[i]; } LL res=1e12; for(int i=0;i<=maxv;i++) { res=min(res,abs(get(i)-S)); } cout<<res; return 0; }
观察每个区间的值 : $$ y_i=\sum\limits_{j=l_i}^{r_i}[w_j \ge W] \times \sum\limits_{j=l_i}^{r_i}[w_j \ge W]v_j$$ 当 增大时,区间;中满足要求的会減少,同时所有,因此 的值也会减少。由于 ,所以 随 单调递减。
因此我们可以二分出距离 最近的值。
剩下的问题是当 确定之后,我们如何快速求出每个 。这里可以预处理出所有满足 的元素的前缀和,之后可以 0(1)时间求出每个区间中所有 的和以及满足要求的元素个数。
时间复杂度分析
总共二分 次,每次预处理前缀和的计算量是 ,求的计算量是 。
因此总时间复杂度是 。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=200010; int n,m; LL S; int w[N],v[N]; int l[N],r[N]; int cnt[N]; LL sum[N]; LL get(int W) //获取选取W的检验值 { for(int i=1;i<=n;i++) { if(w[i]>=W) { sum[i]=sum[i-1]+v[i]; cnt[i]=cnt[i-1]+1; } else { sum[i]=sum[i-1]; cnt[i]=cnt[i-1]; } } LL res=0; for(int i=1;i<=m;i++) { res=res+(cnt[r[i]]-cnt[l[i]-1])*(sum[r[i]]-sum[l[i]-1]); } return res; } int main() { cin>>n>>m>>S; for(int i=1;i<=n;i++) { cin>>w[i]>>v[i]; } for(int i=1;i<=m;i++) { cin>>l[i]>>r[i]; } int l=0,r=1e6; while(l<r) { int mid=l+r+1>>1; if(get(mid)>=S) l=mid; //说明y>=S,说明y应该小一些,也就是w需要大一些 else r=mid-1; } cout<<min(abs(get(r)-S),abs(S-get(r+1))); return 0; }
- 1
Information
- ID
- 1092
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 10
- Tags
- # Submissions
- 3
- Accepted
- 1
- Uploaded By