首页 > 其他分享 >abc366

abc366

时间:2024-08-11 17:17:48浏览次数:9  
标签:int sum pair using abc366 dp define

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\)动态维护即可

代码

#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背包),转移方程见代码

代码

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

标签:int,sum,pair,using,abc366,dp,define
From: https://www.cnblogs.com/mgnisme/p/18353632

相关文章

  • CF1998 div2 & abc366
    1CF1.1B被诈骗了。我们的构造要向“每个区间只有1个数不一样考虑”。1.2C比较难。但是出的好。注意到如果我们不删除中位数这个位置的数,那么那个数是一定的。所以我们可以把\(k\)加到最大的可以加的数上,统计答案就在这个数,然后二分算中位数即可。其它策略?我们可不......
  • ABC366整理
    ABC366整理:C:用一个变量存储背包内现有的球种类数注:可能会重模拟即可简单的C++code:#include<bits/stdc++.h>//#include<windows.h>//#include<unistd.h>usingnamespacestd;#defineendl'\n'#defineTRACE1#definetcoutTRACE&&cout#define......
  • ABC366简要题解
    C直接维护一个桶,表示每个元素当前的出现次数。再利用这个桶直接维护答案即可。D三维前缀和模板题。E注意到答案中只会出现\(O(n)\)个不同\(x\),以及\(O(n)\)个不同的\(y\)。于是单独考虑\(x\)和\(y\),最后尺取求一下答案即可。F首先我第一个尝试的思路是贪心,但是......
  • ABC366-D 题解
    三维前缀和板子。三维前缀和可以类似二维前缀和来做,先给一下二维前缀和数组的计算方法:\[sum_{i,j}=a_{i,j}+sum_{i-1,j}+sum_{i,j-1}-sum_{i-1,j-1}\]同样的,可以写出三维前缀和数组的计算方法:\[sum_{i,j,k}=a_{i,j,k}+sum_{i,j,k-1}+sum_{i,j-1,k}+sum_{i-1,j,k}-sum_{i,j-1,k......
  • ABC366
    A[link](https://atcoder.jp/contests/abc366/tasks/abc366_a]判断一下少的那个人加上剩下的所有票是否会超过另一个人,如果超过,不确定,否则目前票多的必胜。神奇的代码#include<bits/stdc++.h>usingnamespacestd;signedmain(){ intn,a,b; cin>>n>>a>>b; i......