abc 366 E+F(曼哈顿距离 x y 两个坐标分别计算)(贪心+01背包)

2024-08-25 04:44

本文主要是介绍abc 366 E+F(曼哈顿距离 x y 两个坐标分别计算)(贪心+01背包),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

E题:
在这里插入图片描述
题意:给定的 xi yi 。求有多少点 到给人 若干定点 的曼哈顿距离 和 小于等于D.
因为D 最大时 1e6,-1e6<=xi<=1e6。
所以 可能的 点 的 x 的范围是 [-2e6 2e6]
同理 y 的 范围 一样。

将 x y 分开讨论。
我们可以枚举 某个x 的 个数,找到合法的y 的个数。两者相乘。相乘之后的值累加起来。就是结果。
碰到绝对值,利用排序,来消除绝对值。将 xi yi 都分别排序。

在这里插入图片描述
求 f (f的数值最大是1e6,直接开数值桶来维护),我们要遍历 -2e6 到 2e6 的所有范围。
不断的动态维护前缀和后缀。
因为要维护 t 的数值。
所以我们干脆 一个区间一个区间的遍历。(xi 将 [-2e6, 2e6 ]划分成的区间 )
例如 【-1e6,a[0]),[a[0],a[1])……因为我们每次搜索的区间是左闭右开的,所以最后一个是2e6+1(多的加1,就是因为右端点是开的)
这样 t 的 数值,很好确定。

#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 1e6 + 5;
int cnt1[N], cnt2[N];
void solve()
{int n;cin >> n;int d;cin >> d;vector<int> a(n + 2);vector<int> b(n + 2);for (int i = 1; i <= n; i++){cin >> a[i] >> b[i];}a[0] = -2e6;a[n + 1] = 2e6 + 1;b[0] = -2e6;b[n + 1] = 2e6+1;auto fun = [&](vector<int> &a, int *cnt) -> void{sort(a.begin(), a.end());int pre = 0;int sub = 0;for (int i = 1; i <= n; i++){sub += a[i];}for (int x = -2e6; x < a[1]; x++){int dis = sub - n * x;if (dis <= d)cnt[dis]++;}for (int i = 1; i <= n; i++){pre += a[i];sub -= a[i];for (int x = a[i]; x < a[i + 1]; x++){int dis = (2 * i - n) * x - pre + sub;if (dis <= d)cnt[dis]++;}}};fun(a,cnt1);fun(b,cnt2);for (int i=1;i<=d;i++){cnt2[i]+=cnt2[i-1];}int ans=0;for (int i=0;i<=d;i++){ans+=cnt1[i]*cnt2[d-i];}cout<<ans<<"\n";
}
signed main()
{std::cin.tie(nullptr)->sync_with_stdio(false);int t;t = 1;while (t--){solve();}return 0;
}

F
在这里插入图片描述
我们可以猜测,各个函数的嵌套顺序是 可以贪心的。下面是证明。
在这里插入图片描述

我们确定了相对的顺序。从 n 个里面选出来k 个,每一个函数有选和不选两种选择。是 01 背包的问题。
dp[0]=1;

#include <bits/stdc++.h>
using namespace std;
#define int long long 
void solve()
{int n,k;cin>>n>>k;vector<pair<int,int>>a(n);for (int i=0;i<n;i++){cin>>a[i].first>>a[i].second;}auto cmp=[&](pair<int,int>&x,pair<int,int>&y)->bool{return (1.0*x.first-1)/(1.0*x.second)<(1.0*y.first-1)/(1.0*y.second);};sort(a.begin(),a.end(),cmp);vector<int>dp(k+1);int ans=0;dp[0]=1;for (int i=0;i<n;i++){for (int j=k;j>=1;j--){dp[j]=max(dp[j],dp[j-1]*a[i].first+a[i].second);}}cout<<dp[k]<<"\n";}
signed main()
{std::cin.tie(nullptr)->sync_with_stdio(false);int t;t = 1;// cin>>t;while (t--){solve();}return 0;
}

这篇关于abc 366 E+F(曼哈顿距离 x y 两个坐标分别计算)(贪心+01背包)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104577

相关文章

poj2576(二维背包)

题意:n个人分成两组,两组人数只差小于1 , 并且体重只差最小 对于人数要求恰好装满,对于体重要求尽量多,一开始没做出来,看了下解题,按照自己的感觉写,然后a了 状态转移方程:dp[i][j] = max(dp[i][j],dp[i-1][j-c[k]]+c[k]);其中i表示人数,j表示背包容量,k表示输入的体重的 代码如下: #include<iostream>#include<

hdu2159(二维背包)

这是我的第一道二维背包题,没想到自己一下子就A了,但是代码写的比较乱,下面的代码是我有重新修改的 状态转移:dp[i][j] = max(dp[i][j], dp[i-1][j-c[z]]+v[z]); 其中dp[i][j]表示,打了i个怪物,消耗j的耐力值,所得到的最大经验值 代码如下: #include<iostream>#include<algorithm>#include<

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

usaco 1.3 Barn Repair(贪心)

思路:用上M块木板时有 M-1 个间隙。目标是让总间隙最大。将相邻两个有牛的牛棚之间间隔的牛棚数排序,选取最大的M-1个作为间隙,其余地方用木板盖住。 做法: 1.若,板(M) 的数目大于或等于 牛棚中有牛的数目(C),则 目测 给每个牛牛发一个板就为最小的需求~ 2.否则,先对 牛牛们的门牌号排序,然后 用一个数组 blank[ ] 记录两门牌号之间的距离,然后 用数组 an

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc