Educational Round 64 题解

前言:

这场太难了……我一个紫名只打出两题……(虽说感觉的确发挥不够好)

一群蓝绿名的dalao好像只打了两题都能升分的样子……

庆幸的是最后A出锅然后unr了>///<

写一波题解纪念这次失败的edu吧。


A

看起来很像sb题……实则细节巨多……

一开始分了六类就过了……

然后重测一遍就挂了……所以出题人做错自己出的题了?

注意特判三角形在圆里又在一个正方形的情况,会少一个点。


B

一开始想的是把相同的字母压一起,然后按ace...ybdf...z这样排。

然而出现一些毒瘤还是不行,然后就一直在想调换首位什么的,一直挂一直挂……

最后还是zz先切了……在奇数中选一个,偶数中选一个,它们不相邻,然后奇序列和偶序列之间插入这两个,就不会有这种问题了。


C

一眼贪心,一发WA。这么简单的正解没想到……

二分,每次把 $i(1\le i\le mid)$ 和 $n-mid+i$ 匹配看看行不行。


D

看起来是个树形dp,$f[u][0/1/2/3]$ 表示从下往上到 $u$ 分别是全 $0$,全 $1$,先 $0$ 再 $1$,先 $1$ 再 $0$ 的路有多少。

赛场上想出了然而打炸了……赛后又调出来了……。

具体转移看代码吧,应该能看懂的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=400040;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,el,head[maxn],to[maxn],w[maxn],nxt[maxn];
ll f[maxn][4],ans;
inline void add(int a,int b,int c){
    to[++el]=b;nxt[el]=head[a];head[a]=el;w[el]=c;
}
void dfs(int u,int F){
    ll s=0;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(v==F) continue;
        dfs(v,u);
        if(w[i]){
            s+=f[u][0]*(f[v][1]+1);
            s+=f[u][1]*(f[v][0]+2*f[v][1]+f[v][2]+2);
            s+=f[u][2]*(f[v][1]+1);
            s+=f[v][0]+2*f[v][1]+f[v][2]+2;
            f[u][1]+=f[v][1]+1;
            f[u][2]+=f[v][2]+f[v][0];
        }
        else{
            s+=f[u][0]*(2*f[v][0]+f[v][1]+f[v][3]+2);
            s+=f[u][1]*(f[v][0]+1);
            s+=f[u][3]*(f[v][0]+1);
            s+=2*f[v][0]+f[v][1]+f[v][3]+2;
            f[u][0]+=f[v][0]+1;
            f[u][3]+=f[v][3]+f[v][1];
        }
    }
    ans+=s;
}
int main(){
    n=read();
    FOR(i,1,n-1){
        int u=read(),v=read(),w=read();
        add(u,v,w);add(v,u,w);
    }
    dfs(1,0);
    cout<<ans;
}
View Code

后面的,以后会做了再说吧……

 

转载于:https://www.cnblogs.com/1000Suns/p/10801927.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起和终,以及每条道路的起、终、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起和终作为一个有向边的起和终,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起到终的最短路径。在这个过程中,我们需要记录到每个的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起到终的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个的最小费用和最小长度进行松弛操作。具体来说,当我们从一个 u 经过一条边 (u,v) 到达另一个 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值