自学内容网 自学内容网

牛客周赛 Round 62(期望、DFS、主席树、DP、逆推DP)

牛客周赛 Round 62(期望、DFS、主席树、DP、逆推DP)

A. 小红的字符移动

交换前两个元素的位置即可。

#include<bits/stdc++.h>
using namespace std;

int main() {

string s;
    cin >> s;
    
    swap(s[0], s[1]);
    cout << s << endl;
    
return 0;
}

B. 小红的数轴移动

根据题意模拟即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;


int main() {

ll n, x;
cin >> n >> x;

    ll res = 0, s;
    while(n--){
        if(x == 0) break;
        cin >> s;
        res += s;
        if(x > 0) x -= s;
        else x += s;
    }
 
    cout << res << endl;

return 0;
}

C. 小红的圆移动

对于原点不在圆内的圆,设圆心为(x,y),其移动的代价为: ( r − x 2 + y 2 ) ∗ Π ∗ r 2 (r - \sqrt{x^2+y^2}) * Π * r^2 (rx2+y2 )Πr2

(让圆在圆心与原点的连线上移动为最优移动方案)

根据需要依次移除代价最小的圆即可。

#include<bits/stdc++.h>
using namespace std;

const double pi = 3.14159265358979324;

int main() {

int n, k;
cin >> n >> k;

vector<double> tmp;
double x, y, r;
for(int i = 1; i <= n; i++){
cin >> x >> y >> r;
double len = x * x + y * y;
if(len < r * r){// 避免精度问题,比较时不开根号
len = (r - sqrt(len)) * pi * r * r;
tmp.push_back(len);
}
}

sort(tmp.begin(), tmp.end());

double res = 0;
for(int i = 0; tmp.size() - i > k; i++) res += tmp[i];
printf("%.10lf", res);

return 0;
}

D. 小红的树上移动 (期望、DFS)

根据题意,小红只能由根向下走,不能走回头路,到叶子节点上停止。

即,树上每个分支都会对答案有贡献,每个分支的贡献为: 分支高度 ∗ ∏ ( 1 / x s o n ) , x ∈ 分支上结点 , x s o n 表示 x 的孩子数 分支高度 * \prod(1 / x_{son}),x \in 分支上结点, x_{son} 表示 x 的孩子数 分支高度(1/xson),x分支上结点,xson表示x的孩子数

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const ll mod = 1e9 + 7;
const int maxn = 1e5 + 5;

vector<int> e[maxn];

ll qpow(ll a, ll b){
ll res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}

ll dfs(int f, int u, ll cnt, ll p){
if(f != 0 && e[u].size() == 1) return cnt * qpow(p, mod-2) % mod;
ll res = 0;
for(auto v: e[u]){
if(v == f || v == 0) continue; // 0 不参与计算
res += dfs(u, v, cnt+1, p*(e[u].size()-1)%mod);
res %= mod; 
}
return res;
}

int main() {

int n;
cin >> n;
int x, y;
for(int i = 2; i <= n; i++){
cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}

e[1].push_back(0);// 假设 1 的父亲为0
ll res = dfs(0, 1, 1, 1);

    if(n == 1) res = 1;
cout << res << endl;

return 0;
}

E. F. 小红的中位数查询(主席树)

主席树板子题,求区间(l,r)的中位数,即求区间(l,r)的第 (r - l ) / 2 + 1大。即,主席树求第k大。

这个板子是我随便搜索,大家可自行学习。传送门

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
int n,m,a[N];
struct zxTree {
int ls,rs,sum;//左右儿子,区间内元素个数
#define ls(x) tr[x].ls
#define rs(x) tr[x].rs
#define sum(x) tr[x].sum
} tr[N*40];//注意数组大小
int sz = 0;//不同版本的树的总数
int root[N];//root[i]存放第i棵树的树根的编号
int BuildTree(int l,int r) {
/*建树,和普通线段树相同*/
int rt = ++sz;
sum(rt) = 0;
if(l == r) return rt;
int mid = l+r>>1;
ls(rt) = BuildTree(l,mid);
rs(rt) = BuildTree(mid+1,r);
return rt;
}
int updata(int pre,int l,int r,int x) {
/*新建一棵树,其比pre树多一个元素x*/
int rt = ++sz;
tr[rt] = tr[pre];
sum(rt)++;
if(l == r) return rt;
int mid = l+r>>1;
if(x <= mid) ls(rt) = updata(ls(pre),l,mid,x);
else rs(rt) = updata(rs(pre),mid+1,r,x);
return rt;
}
int ask(int pre,int rt,int l,int r,int k) {
/*  依次是:上一个树根,当前树根,区间左右端点,所求区间第k大
    返回该区间第k大数的下标 */
if(l >= r) return l;
int res = sum(ls(rt)) - sum(ls(pre));
int mid = l+r>>1;
if(res >= k) return ask(ls(pre),ls(rt),l,mid,k);
else return ask(rs(pre),rs(rt),mid+1,r,k-res);
}
int tmp[N];
int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) scanf("%d",a+i),tmp[i] = a[i];
//离散化
sort(tmp+1,tmp+1+n);
int tot = unique(tmp+1,tmp+1+n)-tmp-1;
root[0] = BuildTree(1,tot);
for(int i = 1; i <= n; i++) {
int x = lower_bound(tmp+1,tmp+1+tot,a[i])-tmp;
root[i] = updata(root[i-1],1,tot,x);
}
//利用主席树可以加减原理计算
for(int i = 1,l,r,k; i <= m; i++) {
scanf("%d%d",&l,&r);
k = (r - l + 1) / 2 + 1;
int x = ask(root[l-1],root[r],1,tot,k);
printf("%d\n", tmp[x]);
}
return 0;
}

G. 小红的数轴移动(二)(DP、逆推DP)

由于 x 可能由正负,下标整体偏移 10000。

d p ( i , M + j ) dp_{(i, M+j)} dp(i,M+j) 表示选择前 i 个物品,到达位置 j 需要的最小代价,其中 M 表示偏移量。

维护好dp数组后,判断是否需要全选,即是否走到了 x = 0。

  1. 如果没走到 x = 0 的位置,则任意顺序走即可。
  2. 如果走到 x = 0 的位置,则需要根据dp方程,逆推出转移顺序。
#include<bits/stdc++.h>
using namespace std;

const int INF = 1e9;
const int maxn = 1e4 + 5;
const int M = 1e4;// 偏移量 

int a[105], dp[105][maxn*3];
vector<int> pos[105];

int main() {

memset(dp, 0x3f, sizeof(dp));// 初始化一个较大值 
//cout << dp[5][100];

int n, x;
cin >> n >> x;
int sum = 0;
set<int> s;
for(int i = 1; i <= n; i++){
cin >> a[i];
s.insert(i);
sum += a[i];
pos[a[i]].push_back(i);
}

dp[0][M+x] = 0;// dp[i][j] 表示前 i 个物品走到 j 需要的代价,注意这时候没有限制移动方向
for(int i = 1; i <= n; i++){
for(int j = -10000; j <= 10000; j++) dp[i][M+j] = dp[i-1][M+j]; // 不选当前a[i] 
for(int j = -10000; j <= 10000; j++){
if(j + a[i] <= 10000){// 超过这个范围就走不回来了 
dp[i][M + j + a[i]] = min(dp[i][M + j + a[i]], dp[i-1][M + j] + a[i]);
}
if(j - a[i] >= -10000){
dp[i][M + j - a[i]] = min(dp[i][M + j - a[i]], dp[i-1][M + j] + a[i]);
}
} 
}

if(dp[n][M] == dp[0][0]){// dp 的值等于初始值,表示没走到原点,即不会停,任意走就行 
cout << sum << endl;
for(int i = 1; i <= n; i++) cout << i << " ";
cout << endl;
}
else{// 可以走到原点,倒推DP 
cout << dp[n][M] << endl;
vector<int> to_left, to_right; // 记录都是那些往左走了,那些往右走了
int j = 0, val = dp[n][M];
for(int i = n; i >= 1; i--){// 从后往前倒推 
if(dp[i-1][M+j] == dp[i][M+j]) continue; // 不选当前 a[i]

if(j + a[i] <= 10000 && dp[i-1][M + j + a[i]] == dp[i][M + j] - a[i]){// (i, M+j) 可以由 (i-1, m+j+a[i]) 得到 
to_left.push_back(pos[a[i]].back()); // 从左往右走a[i]
s.erase(pos[a[i]].back());// 这个元素已经用过了
pos[a[i]].pop_back();`// 相同值,可能有多个,选一个就行
j += a[i];
val -= a[i];
}

if(j - a[i] >= -10000 && dp[i-1][M + j - a[i]] == dp[i][M + j] - a[i]){// (i, M+j) 可以由 (i-1, m+j-a[i]) 得到 
to_right.push_back(pos[a[i]].back());// 从右往左走a[i]
s.erase(pos[a[i]].back());
pos[a[i]].pop_back();
j -= a[i];
val -= a[i];
}
}


vector<int> ans;
while(x != 0){
if(x < 0){// 小于零就在 左往右走 中取一个
x += a[to_right.back()];
ans.push_back(to_right.back());
to_right.pop_back();
}
else{
x -= a[to_left.back()];
ans.push_back(to_left.back());
to_left.pop_back();
}
}

for(auto item : ans) cout << item << " ";
for(auto item : s) cout << item << " ";
}


return 0;
}

原文地址:https://blog.csdn.net/mldl_/article/details/142737518

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!