codeforces 985C. Liebig's Barrels
n表示桶的个数,k表示每个桶的木板数目,l表示任意两个桶中的最短木板的差值的上限。
思路比较明确,找出最短木板的长度记为 m,那么每个桶的最短木板的范围在[ m,m+l]之间。、
在计算和的时候,思路有点混乱,始终没有找到正确的方法。
其实可以这样想:
- 如果长度小于m+l的木板数目小于n,那么无解
- 如果正好等于,就是前n个木板的和
- 如果长度小于m+l的木板数目大于n,就需要跳过一些木板,同时要保证最后的和是最大的
针对第三种情况,枚举n个水桶,每个水桶最多跳过k-1个木块,同时保证剩下的范围在[ m,m+l ]之间的木板的个数可以分给剩下的水桶
int ptr=0; for(int i=0;i<n;i++){ sum+=stave[ptr++]; for(int v=0;v<k-1;v++){ if(pos-ptr>n-i-1)ptr++; else break; } }
非常简短巧妙的代码
整题的代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<string> #include<vector> #include<queue> #include<map> #include<unordered_map> #define DEBUG(x) cout<<#x<<" = "<<x<<endl using namespace std; const int MAXN=1e5+10; const int INF=0x3f3f3f3f; typedef long long ll; ll stave[MAXN]; int n,k,l; int main() { // freopen("in.txt","r",stdin); scanf("%d%d%d",&n,&k,&l); int t=n*k; ll m; for(int i=0;i<t;i++){ scanf("%I64d",&stave[i]); m=min(m,stave[i]); m=i==0?stave[i]:min(stave[i],m); } ll M=m+(ll)l; sort(stave,stave+t); int pos=upper_bound(stave,stave+t,M)-stave; if(pos<n)printf("%d\n",0); else { ll sum=0; int ptr=0; for(int i=0;i<n;i++){ sum+=stave[ptr++]; for(int v=0;v<k-1;v++){ if(pos-ptr>n-i-1)ptr++; else break; } } printf("%I64d\n",sum); } }