abc366

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;
}