E
解题思路
这题求的是满足\(\sum^n_{i=1}(|x-x_i|+|y-y_i|)\leq D\) 的坐标\((x,y)\) 的数目,由于是求和,所以\(x,y\) 之间是相互独立的
- 第一步,先分别求出满足\(\sum^n_{i=1}|x-x_i|\leq D\) 和\(\sum^n_{i=1}|y-y_i|\leq D\) 的\(sum_x\)和\(sum_y\),这两者是等价的
- 第二步,对第一步求出的结果排序,枚举\(sum_x\),然后用二分或者双指针去求满足的\(sum_y\)的数量,累计即为答案
对于第一步,先对数组\(x\)进行排序,注意到\(x\)的范围仅为\([-10^6,10^6]\),\(D \leq 10^6\),所以我们可以从\(min\_x-10^6\)枚举到\(max\_x+10^6\),枚举出符合\(sum_x\leq D\)的\(sum_x\),最开始求一遍\(sum_x\),后面枚举时对\(sum_x\)动态维护即可
代码
c
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
using pii = pair<int, int>;
using piii = pair<int, pii>;
using pll=pair<ll,ll>;
using plll=pair<ll,pii>;
#define fi first
#define se second
const int INF = 0x3f3f3f3f;
void solve() {
int n,d;
cin>>n>>d;
vector<int> a(n),b(n);
for(int i=0;i<n;i++){
cin>>a[i]>>b[i];
}
auto get=[&](vector<int>&a){
vector<int> res;
sort(a.begin(),a.end());
if(a.back()-a.front()>d) return res;//没啥用的剪枝
int st=a.front()-d;
ll sum=0;
for(int i=0;i<n;i++) sum+=abs(a[i]-st);
bool tag=false;
int cnt=0;
for(int i=st;i<=a.back()+d;i++){
if(sum<=d) res.push_back(sum);
if(sum<=d) tag=true;//没啥用的剪枝
if(tag&&sum>d) break;//没啥用的剪枝
while(cnt<n&&i==a[cnt]) cnt++;
sum+=cnt-(n-cnt);
}
sort(res.begin(),res.end());
return res;
};
vector<int> xs=get(a),ys=get(b);
ll ans=0;
for(int i=0,j=ys.size()-1;i<xs.size();i++){//双指针
while(j>=0&&ys[j]+xs[i]>d) j--;
ans+=j+1;
}
cout<<ans<<endl;
}
int main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
int _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}
F
解题思路
我们先把选的组合固定,必然选的组合长度为\(K\),下面就要考虑组合的顺序
对于\(A_i,B_i,A_{i+1},B_{i+1}\),假设第\(i\)在前,结果为\(A_{i+1}*(A_i*x+B_i)+B_{i+1}\),即为\(A_iA_{i+1}*x+A_{i+1}B_i+B_{i+1}\),假设第\(i+1\)在前,结果为\(A_iA_{i+1}*x+A_iB_{i+1}+B_i\),如果前者顺序由于后者的顺序,那么前者式子大于后者,化简得\((A_{i+1}-1)*B_i>(A_i-1)*B_{i+1}\),按这样的优先级对数对进行排序,从前往后顺序选一定是最优的
顺序确定了,考虑选那些数对,我们定义\(dp[i][j]\)为前\(i\)个数对选了\(j\)个数对时的最大值,并用滚动数组优化为一维(类似01背包),转移方程见代码
代码
c
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
using pii = pair<int, int>;
using piii = pair<int, pii>;
using pll=pair<ll,ll>;
using plll=pair<ll,pii>;
#define fi first
#define se second
const int INF = 0x3f3f3f3f;
void solve() {
int n,k;
cin>>n>>k;
vector<pii> tup(n);
for(int i=0;i<n;i++){
auto &[a,b]=tup[i];
cin>>a>>b;
}
sort(tup.begin(),tup.end(),[&](pii A,pii B){
return (A.fi-1)*B.se<(B.fi-1)*A.se;
});
vector<ll> dp(k+1);
dp[0]=1;
for(int i=0;i<n;i++){
for(int j=k-1;j>=0;j--){
if(dp[j])
dp[j+1]=max(dp[j+1],dp[j]*tup[i].fi+tup[i].se);
}
}
cout<<dp[k]<<endl;
}
int main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
int _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}