ARC135 部分题解

竞赛地址

https://atcoder.jp/contests/arc135/tasks

A - Floor, Ceil - Decomposition

https://atcoder.jp/contests/arc135/tasks/arc135_a

题解

数学题。
给一个正整数 X X X f ( x ) f(x) f(x) 是一通操作后乘积最大值。
假设 X − = ⌊ x 2 ⌋ ,   X + = ⌈ x 2 ⌉ X_-=\lfloor \frac{x}{2} \rfloor,\ X_+=\lceil \frac{x}{2} \rceil X=2x, X+=2x。我们可以写出
f ( 1 ) = 1 f ( X ) = m a x ( X , f ( X − ) × f ( X + ) )   ∀ x ≥ 2 f(1)=1\\ f(X)=max(X, f(X_-) \times f(X_+))\ \forall x \ge 2 f(1)=1f(X)=max(X,f(X)×f(X+)) x2
下面我们来推导数学公式
f ( X − ) × f ( X + ) ≥ X − × X + ≥ X − 1 2 × X 2 ≥ X − 1 4 × X f(X_-) \times f(X_+) \ge X_- \times X_+ \ge \frac{X-1}{2} \times \frac{X}{2} \ge \frac{X-1}{4} \times X f(X)×f(X+)X×X+2X1×2X4X1×X
这样,我们知道当 X ≥ 4 X \ge 4 X4 的时候, X − 1 4 × X ≥ X \frac{X-1}{4} \times X \ge X 4X1×XX
因此:
f ( X ) = X   ∀ X ≤ 4 f ( X ) = f ( X − ) × f ( X + )   ∀ X ≥ 5 f(X)=X\ \forall X \leq 4\\ f(X)=f(X_-) \times f(X_+)\ \forall X \ge 5 f(X)=X X4f(X)=f(X)×f(X+) X5
这样,我们可以用 DFS 来实现。
下面我们来看一下数据范围, 1 ≤ X ≤ 1 0 18 1 \leq X \leq 10^{18} 1X1018,数据很大,需要使用记忆化搜索来优化。

AC 代码

#include<bits/stdc++.h>
using namespace std;
using LL=long long;
using PLL=pair<LL,LL>;

const LL MO=998244353;

unordered_map<LL, LL> M;

LL dfs(LL x) {
    if (M.count(x)) {
        return M[x];
    }
    M[x]=x;
    if (x<=4) {
        return M[x];
    }
    return M[x]=(dfs(x/2)*dfs((x+1)/2))%MO;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    LL x;
    cin>>x;

    cout<<dfs(x)<<"\n";

    return 0;
}

B - Sum of Three Terms

https://atcoder.jp/contests/arc135/tasks/arc135_b

题解

又是数学题。
假设序列 A A A 为满足条件的序列,这样
S i = A i + A i + 1 + A i + 2 ⇒ A i + 2 = S i − A i − A i + 1 S_i = A_i+A_{i+1}+A_{i+2} \Rightarrow A_{i+2}=S_i-A_i-A_{i+1} Si=Ai+Ai+1+Ai+2Ai+2=SiAiAi+1
i = 1 i=1 i=1 的时候, A 3 = S 1 − A 1 − A 2 A_3=S_1-A_1-A_2 A3=S1A1A2,这个方程中有 3 3 3 个未知数,这样我们假设 A 1 = a ,   A 2 = b A_1=a,\ A_2=b A1=a, A2=b,我们可以推导出如下
{ A 1 = a A 2 = b A 3 = S 1 − A 1 − A 2 = S 1 − a − b A 4 = S 2 − A 2 − A 3 = S 2 − S 1 + a A 5 = S 3 − A 3 − A 4 = S 3 − S 2 + b A 6 = S 4 − A 4 − A 5 = S 4 − S 3 − a − b A 7 = S 5 − A 4 − A 6 = S 5 − S 4 + a A 8 = S 6 − A 6 − A 7 = S 6 − S 5 + b . . . \begin{cases} A_1=a \\ A_2=b \\ A_3=S_1-A_1-A_2=S_1-a-b \\ A_4=S_2-A_2-A_3=S_2-S_1+a \\ A_5=S_3-A_3-A_4=S_3-S_2+b \\ A_6=S_4-A_4-A_5=S_4-S_3-a-b\\ A_7=S_5-A_4-A_6=S_5-S_4+a \\ A_8=S_6-A_6-A_7=S_6-S5+b\\ ... \end{cases} A1=aA2=bA3=S1A1A2=S1abA4=S2A2A3=S2S1+aA5=S3A3A4=S3S2+bA6=S4A4A5=S4S3abA7=S5A4A6=S5S4+aA8=S6A6A7=S6S5+b...
这样,我们就知道了规律。下面我们需要知道什么时候有解。
解的存在性,我们可以使用一个最简单的序列 S 1 , S 2 , S 3 S_1, S_2, S_3 S1,S2,S3 是否存在一对 ( a , b ) (a,b) (a,b) 满足,这样可得。

{ S 1 ≤ a S 2 ≤ b a + b ≤ S 3 \begin{cases} S_1 \leq a\\ S_2 \leq b\\ a+b \leq S_3 \end{cases} S1aS2ba+bS3
所以,
S 1 + S 2 > S 3 S_1+S_2>S_3 S1+S2>S3 时候,问题无解。
S 1 + S 2 ≤ S 3 ,   ( a , b ) = ( S 1 , S 2 ) S_1+S_2 \leq S_3,\ (a,b)=(S_1,S_2) S1+S2S3, (a,b)=(S1,S2),存在解。
这样,本题就变成一个模拟题。

AC代码

#include<bits/stdc++.h>
using namespace std;
using LL=long long;
using PLL=pair<LL,LL>;

const int N=3e5+10;
LL s[N];
LL a[N];

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    LL n;
    cin>>n;
    for (LL i=1; i<=n; i++) {
        cin>>s[i];
    }

    LL sum=0;
    LL c1=0;
    for (LL i=1; i<n; i+=3) {
        sum+=s[i]-s[i+1];
        c1=max(c1, sum);
    }
    sum=0;
    LL c2=0;
    for (LL i=2; i<n; i+=3) {
        sum+=s[i]-s[i+1];
        c2=max(c2, sum);
    }
    sum=0;
    LL c3=0;
    for (LL i=3; i<n; i+=3) {
        sum+=s[i]-s[i+1];
        c3=max(c3, sum);
    }

    if (c1+c2+c3>s[1]) {
        cout<<"No\n";
        return 0;
    }
    a[1]=c1;a[2]=c2;a[3]=s[1]-c1-c2;
    for (LL i=2; i<=n; i++) {
        a[i+2]=s[i]-a[i]-a[i+1];
    }
    cout<<"Yes\n";
    for (LL i=1; i<=n+2; i++) {
        cout<<a[i]<<" ";
    }
    cout<<"\n";

    return 0;
}
  • 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
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值