在二维平面上有n个蹦床,每个蹦床都有一个弹力值
p
,你自己有一个初始的弹跳能力S
,从一个点蹦到另一个点的条件是 P i ∗ S > = ∣ x i − x j ∣ + ∣ y i − y j ∣ P_i * S >= |x_i-x_j|+|y_i - y_j| Pi∗S>=∣xi−xj∣+∣yi−yj∣问
S
最小为多少时,满足可以使得从任意一个点出发,能到达其他的任何一个点
根据上面那个式子,不难发现 S > = ⌈ ∣ x i − x j ∣ + ∣ y i − y j ∣ p i ⌉ S >= \lceil{\frac{|x_i-x_j|+|y_i-y_j|}{p_i}}\rceil S>=⌈pi∣xi−xj∣+∣yi−yj∣⌉
我们可以根据这个,作为两个点之间的距离,跑
floyed
维护出最短路上的最大权值,枚举每个点为起点,找出每个点到其他点的路径的最大值,取一个最小值即可或者可以二分答案,然后dfs爆搜,但是这种方法我觉得复杂度太大没敢写
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
ll n, m, k, op, x;
struct ran{
ll x, y;
ll p;
}tr[MAX];
ll dis[205][205];
void work(){
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> tr[i].x >> tr[i].y >> tr[i].p;
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
dis[i][j] = (abs(tr[i].x - tr[j].x) + abs(tr[i].y - tr[j].y) + tr[i].p - 1) / tr[i].p;
}
}
for(int k = 1; k <= n; ++k){
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
dis[i][j] = min(dis[i][j], max(dis[i][k] , dis[k][j]));
}
}
}
ll ans = 1e18;
for(int i = 1; i <= n; ++i){
ll cnt = 0;
for(int j = 1; j <= n; ++j){
cnt = max(cnt, dis[i][j]);
}
ans = min(ans, cnt);
}
cout << ans << endl;
}
int main(){
io;
work();
return 0;
}
你现在有
n
元,你可以花c[i]
元钱,使得当前获得的价值乘10 + i,最开始手里的价值为0,问最多能获得多大的价值
显然让长度尽可能长是最优的
满足长度最长的情况下,我们再考虑选择一些不会使得长度变小,且值
i
更大的,贪心就行我们先确定结果是输出多少个数字,再去枚举每次输出哪个数字,枚举的时候从9枚举到1,判断剩余的钱减去当前的c[i]后会不会改变总的长度即可
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k, op, x;
int c[10];
void work(){
cin >> n;
for(int i = 1; i <= 9; ++i){
cin >> c[i];
}
int minx = *min_element(c + 1, c + 10);
k = n / minx;
for(int i = 1; i <= k; ++i){
for(int j = 9; j >= 1; --j){
if(n - c[j] >= minx * (k - i)){
n -= c[j];
cout << j;
break;
}
}
}
}
int main(){
io;
work();
return 0;
}
n个点,m条边,每条边的权值都是1,有一些边的端点时0,则说明这条边是不固定的
现在需要输出n个数字,表示将所有不固定的边连接到
i
上去后,1到n的最短路
由于每次都是将所有不固定的边连接到一个相同的点上去,所以我们可以考虑建图的时候,把0作为特殊点,正常建图,然后我们跑两次bfs,分别求出以1为起点和以n为起点的时候的最短路,对于每次连接到
i
的情况,我们分两种情况,一种是不走那种特殊边,则答案就是1到n的最短路,另一种是走特殊边,这个时候我们可以把0看成i
,分两种情况,一种是1到i,再从i到n,另一种情况是1到0,再从i到n,对这三种情况求个最小值就可以
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k, op, x, y;
vector<int>G[MAX];
int dis1[MAX];
int dis2[MAX];
void work(){
cin >> n >> m;
for(int i = 1; i <= m; ++i){
cin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
mem(dis1, inf);
mem(dis2, inf);
queue<int>q;
q.push(1);
dis1[1] = 0;
while(!q.empty()){
int u = q.front();q.pop();
for(auto v : G[u]){
if(dis1[v] != inf)continue;
dis1[v] = dis1[u] + 1;
q.push(v);
}
}
q.push(n);
dis2[n] = 0;
while(!q.empty()){
int u = q.front();q.pop();
for(auto v : G[u]){
if(dis2[v] != inf)continue;
dis2[v] = dis2[u] + 1;
q.push(v);
}
}
for(int i = 1; i <= n; ++i){
int ans = min(dis1[n], min(dis1[i] + dis2[0], dis1[0] + dis2[i]));
if(ans == inf)cout << -1 << ' ';
else cout << ans << ' ';
}
cout << endl;
}
int main(){
io;
work();
return 0;
}