元素魔法
题解
针对
a1g(x1)+a2g(x2)+...
的求职,如果
a1+a2+...=M
的话,可以使用拉格朗日乘子法【此方法需要大家有高数基础,在学高数时应该学过,大概的证明思路,就是对每一个项求一次偏导,然后求极值】
然后上面可以得出一个结论:
当
xi
为一个已知值,而
ai
只和为一个已知值时,得出
sum(xi)sum(ai)=xiai
,取到最优解。
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
const int MAXN = 2e5 + 5;
int k;
double a, w[MAXN];
double ret[MAXN];
int main(){
while(~scanf("%d%lf", &k, &a)){
double sum = 0;
for(int i = 0;i < k;i ++){
scanf("%lf", &w[i]);
sum += w[i];
}
double bl = sum / a;
double ans = 0;
for(int i = 0;i < k;i ++){
ret[i] = w[i] / bl;
ans += w[i] * log(ret[i]);
}
printf("%.5f\n", ans);
for(int i = 0;i < k;i ++){
printf("%.5f%c", ret[i], i == k - 1 ? '\n' : ' ');
}
}
return 0;
}
两个机器人
题解
很简单的BFS,然后用vis优化一下时间,防止重复访问,如果你还想优化的话,可以加一轮检测就是遇到两个障碍就抛弃
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 50 + 5;
char MP[MAXN][MAXN];
bool vis[MAXN][MAXN][MAXN][MAXN];
int N, M;
int adx[2] = {1, 0};
int ady[2] = {0, 1};
int bdx[2] = {-1, 0};
int bdy[2] = {0, -1};
struct State{
int Ax, Ay, Bx, By;
int step;
State(int Ax, int Ay, int Bx, int By, int step):Ax(Ax), Ay(Ay), Bx(Bx), By(By), step(step){}
};
int BFS(){
queue<State> Q;
while(!Q.empty()) Q.pop();
Q.push(State(0, 0, N - 1, M - 1, 0));
vis[0][0][N - 1][M - 1] = true;
while(!Q.empty()){
//printf("-----------\n");
State p = Q.front();
Q.pop();
if(p.Bx == 0 && p.By == 0 && p.Ax == N - 1&& p.Ay == M - 1){
return p.step;
}
//此处加了剪枝
int flagA = 0;
for(int i = 0;i < 2;i ++){
int nAx = p.Ax + adx[i];
int nAy = p.Ay + ady[i];
if(nAx < 0 || nAx >= N || nAy < 0 || nAy >= M || MP[nAx][nAy] == '1'){
flagA ++;
}
}
if(p.Ax != N - 1 && p.Ay != M - 1 && flagA == 2) continue;
int flagB = 0;
for(int i = 0;i < 2;i ++){
int nBx = p.Bx + bdx[i];
int nBy = p.By + bdy[i];
if(nBx < 0 || nBx >= N || nBy < 0 || nBy >= M || MP[nBx][nBy] == '1') {
flagB ++;
}
}
if(p.Bx != 0 && p.By != 0 && flagB == 2) continue;
//此处加了剪枝
for(int i = 0;i < 2;i ++){
int nAx = p.Ax + adx[i];
int nAy = p.Ay + ady[i];
int nBx = p.Bx + bdx[i];
int nBy = p.By + bdy[i];
int flag = 0;
if(nBx == p.Ax && nBy == p.Ay && nAx == p.Bx && nAy == p.By) continue;
if(nAx == nBx && nAy == nBy) continue;
if(nAx < 0 || nAx >= N || nAy < 0 || nAy >= M || MP[nAx][nAy] == '1'){
nAx = p.Ax;
nAy = p.Ay;
flag ++;
}
if(nBx < 0 || nBx >= N || nBy < 0 || nBy >= M || MP[nBx][nBy] == '1') {
nBx = p.Bx;
nBy = p.By;
flag ++;
}
if(flag == 2) continue;
if(vis[nAx][nAy][nBx][nBy]) continue;
vis[nAx][nAy][nBx][nBy] = true;
Q.push(State(nAx, nAy, nBx, nBy, p.step + 1));
}
}
return -1;
}
int main(){
while(~scanf("%d%d", &N, &M)){
for(int i = 0;i < N;i ++){
scanf("%s", MP[i]);
}
memset(vis, false, sizeof(vis));
int ret = BFS();
printf("%d\n", ret);
}
return 0;
}
子树中的最小权值
题解
正如大佬们经常说的,随便搞搞就可以了,很简单,这里引入一些前导知识,首先求一棵树上任意两个节点的路径上的最小值,大家应该都会求,方法呢,一般有几种:
- 用树链剖分,简直裸模板
- 用
DFS
序,然后用线段树啊,RMQ
来实现
这道题目,我个人的实现思路很简单,就是DFS
序,然后一个节点通过ps[]
,和pe[]
来记录该节点包含的子节点的起始节点编号和终止节点编号,然后如果求解这个节点的最小值或者最大值直接query(ps[], pe[])
就可以实现了
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define FIN freopen("input.txt", "r", stdin)
using namespace std;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int ps[MAXN];
int pe[MAXN];
int fp[MAXN];
int nv[MAXN];
int summ[MAXN << 2];
struct Edge {
int u, v, nxt;
} E[MAXN << 1];
int Head[MAXN], tot, sz;
void edge_init() {
tot = 0;
memset(Head, -1, sizeof(Head));
}
void add_edge(int u, int v) {
E[tot].u = u;
E[tot].v = v;
E[tot].nxt = Head[u];
Head[u] = tot ++;
}
void xds_init() {
sz = 0;
}
//DFS序
void dfs(int u, int fa) {
ps[u] = ++ sz;
fp[ps[u]] = u;
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(v == fa) continue;
dfs(v, u);
}
pe[u] = sz;
}
void push_up(int rt) {
summ[rt] = min(summ[rt << 1], summ[rt << 1 | 1]);
}
void build(int l, int r, int rt) {
if(l == r) {
summ[rt] = nv[fp[l]];
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
push_up(rt);
}
void update(int p, int v, int l, int r, int rt) {
if(l == r) {
summ[rt] = v;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) {
update(p, v, lson);
} else {
update(p, v, rson);
}
push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return summ[rt];
}
int mid = (l + r) >> 1;
int ret = INF;
if(L <= mid) {
ret = min(ret, query(L, R, lson));
}
if(R > mid) {
ret = min(ret, query(L, R, rson));
}
return ret;
}
int N;
int main() {
//FIN;
while(~scanf("%d", &N)) {
for(int i = 1; i <= N; i ++) {
scanf("%d", &nv[i]);
}
edge_init();
xds_init();
int x;
for(int i = 2; i <= N; i ++) {
scanf("%d", &x);
add_edge(i, x);
add_edge(x, i);
}
int root = 1;
dfs(root, -1);
build(1, sz, 1);
int q, op, u;
scanf("%d", &q);
while(q --) {
scanf("%d", &op);
if(op == 1) {
scanf("%d%d", &x, &u);
update(ps[x], u, 1, sz, 1);
} else {
scanf("%d", &x);
printf("%d\n", query(ps[x], pe[x], 1, sz, 1));
}
}
}
return 0;
}