CF689题解

CF689

Codeforces Round 361 (Div. 2)

CF689A

link

CF689A题意

题目描述
迈克在海滩游泳时不小心将手机放入水中。他买了一个带有老式键盘的手机。键盘只有十个数字大小的键,位于以下方式:

123
456
789
0

联系人与他的旧手机一起消失了,他现在只能记住他的手指在他输入一些数字时的移动方式。人们可以将手指动作视为连接按下按键的一系列动作。例如,数字“586”的手指移动动作与数字“253”的手指移动动作相同。
Mike通过他的“手指记忆”输入了一个数字并开始调用它,所以他现在担心,有没有其他数字,有相同的手指动作?

输入格式:
输入的第一行包含唯一的整数n(1<=N<=9)表示Mike输入的电话号码中的位数。第二行由1到9组成的n个字符的字符串。

输出格式:
如果没有其他电话号码具有相同的手指移动,则输出“YES”,否则输出“NO”(不带引号)。

CF689A题解

  • 如果出现 0 , 1 , 4 , 7 0,1,4,7 0,1,4,7,那么不能向左移动。
  • 如果出现 0 , 3 , 6 , 9 0,3,6,9 0,3,6,9,那么不能向右移动。
  • 如果出现 1 , 2 , 3 1,2,3 1,2,3,那么不能向上移动。
  • 如果出现 7 , 0 , 9 7,0,9 7,0,9,那么不能向下移动。

判定一下就好了。

CF689A代码

终于做了一道码量正常的题了。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
int n;
int opt[12];
signed main(){
    n = read();
    for(int i = 1;i <= n;i++){scanf("%1d",&opt[i]);}
    bool l = true, r = true,u = true, d = true;
    for(int i = 1;i <= n;i++){
        if(opt[i] == 0){l = r = d = false;continue;}
        if(opt[i] % 3 == 1)l = false;
        if(opt[i] <= 3) u = false;
        if(opt[i] >= 7 && opt[i] != 8) d = false;
        if(opt[i] % 3 == 0)r = false;
    }
    puts((l | r | u | d) ? "NO" : "YES");
    return 0;
}

CF689B

link

CF689B题意

最近,小贝忙于学习,考试和比赛。现在她想出去在城市里逛逛放松一下。

城市有 n n n 个路口,从 1 1 1 n n n 编号。小贝家在 1 1 1 号路口,她从 1 1 1 号路口出发,走过一系列的路口。从路口 i i i 到路口 j j j 需要消耗 ∣ i   −   j ∣ |i - j| ij 单位的能量。她走过一系列路口 p 1 , p 2 , … , p k p_1,p_2,\dots,p_k p1,p2,,pk 消耗的总能量等于 ∑ i = 1 k − 1 ∣ p i − p i − 1 ∣ \sum_{i=1}^{k-1}|p_i-p_{i-1}| i=1k1pipi1

当然,如果没有小路,一味步行是比较无聊的。小路是特别的路径,能让小贝从一个路口到另一个路口只消耗 1 1 1 单位的能量。小贝的城市总共恰好有 n n n 条小路,第 i i i 条小路允许小贝从路口 i i i 走到路口 a i ​ ( i   ≤   a i   ≤   a i + 1 ) a_i​ (i \le a_i \le a_{i+1}) ai(iaiai+1) (但不能反方向走),因此每个路口都有且只有一条小路。严格来说,如果小贝选择一系列路口 p 1   =   1 , p 2 , … , p k p_1 = 1,p_2,\dots,p_k p1= 1,p2,,pk,那么对于每个 1   ≤   i   <   k 1 \le i < k 1 i<k 满足 p i +   1   =   a p i p_i+ 1 = a_{p_i} pi+ 1 =api,并且 a p i ≠ p i a_{p_i}\neq p_i api=pi,从路口 p i p_i pi 到路口 p i + 1 p_{i+1} pi+1,小贝只会消耗1单位能量,而不是| p i   −   p i + 1 p_i - p_{i+1} pipi+1|。 例如,如果小贝选择路口序列 p 1   =   1 , p 2 = a p 1 p_1 = 1,p_2=a_{p_1} p1= 1,p2=ap1,  p 3 = a p 2 p_3=a_{p_2} p3=ap2,  … \dots ,  p k p_k pk =  a p k − 1 a_{p_{k-1}} apk1,她总共消耗 k   −   1 k - 1 k 1 单位的能量。

在她开始闲逛之前,她请你帮她计算从她家到达每个路口最少消耗多少能量。

CF689B题解

翻译题面修了半天还不如自己写一遍呢
按照题意,将 i → a i i\to a_i iai,边权是 1 1 1,然后将 i → i + 1 , i + 1 → i i\to i+1,i+1\to i ii+1,i+1i,边权都是 1 1 1
然后跑Dijkstra就好了。

CF689B代码

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 2e5 + 10,INF = 0x3f3f3f3f;
int n;

int head[maxn], tot;
struct edge{
    int to, nexte, wei;
    edge(int to = 0,int ne = 0,int wei = 0):to(to),nexte(ne),wei(wei){}
}e[maxn << 2];
void add(int u,int v,int w){e[++tot] = edge(v,head[u],w);head[u] = tot;}

int dis[maxn];bool book[maxn];
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii> > que;

signed main(){
    n = read();
    for(int i = 1;i <= n;i++)add(i,read(),1), dis[i] = INF;
    for(int i = 1;i < n;i++) add(i,i + 1,1),add(i + 1,i,1);
    dis[1] = 0;que.push(make_pair(0, 1));
    while(!que.empty()){
        int u = que.top().second;que.pop();
        if(book[u])continue;book[u] = 1;
        for(int i = head[u];i;i = e[i].nexte){
            int v = e[i].to;
            if(dis[v] > dis[u] + e[i].wei){
                dis[v] = dis[u] + e[i].wei;
                que.push(make_pair(dis[v],v));
            }
        }
    }
    for(int i = 1;i <= n;i++)printf("%d ",dis[i]);
    return 0;
}

CF689C

link

CF689C题意

有四个小偷去偷巧克力,四个人偷巧克力的个数是一个等比数列。
给你一个 n n n ,找一个最小数 t t t ,使得在 t t t 内有 n n n 组等比数列成立。

CF689C题解

直接二分答案即可,重要的是读懂题意。

CF689C代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
int n;
int check(int mid){
    int cnt = 0;
    for(int i = 2;i * i * i <= mid;i++)
        cnt += mid / i / i / i;
    return cnt;
}
signed main(){
    n = read();
    int l = 1, r = 1e18 + 1, ans = -1;
    while(l <= r){
        int mid = l + r >> 1;
        if(check(mid) >= n){ans = mid;r = mid - 1;}
        else l = mid + 1;
    }
    if(ans == -1 || check(ans) != n)puts("-1");
    else printf("%lld\n",ans);
    return 0;
}

CF689D

link

CF689D题意

  • 给定序列 a a a 和序列 b b b,长度均为 n n n。问有多少组 ( l , r ) (l,r) (l,r),满足 1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1lrn
    max ⁡ i = l r a i = min ⁡ i = l r b i \max_{i=l}^r a_i=\min_{i=l}^r b_i i=lmaxrai=i=lminrbi
  • 1 ≤ n ≤ 2 × 1 0 5 1\le n\le 2\times 10^5 1n2×105 ∣ a i ∣ , ∣ b i ∣ ≤ 1 0 9 |a_i|,|b_i|\le 10^9 ai,bi109

CF689D题解

对于每一个 r r r max ⁡ \max max 值从 1 → r 1\to r 1r 单调不增, min ⁡ \min min 值从 1 → r 1\to r 1r 单调不降,两者相交的部分就是答案,这东西可以二分,搭配 s t st st 表可以 O ( n log ⁡ n ) O(n\log n) O(nlogn)

CF689D代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 2e5 + 10;
int a[maxn], b[maxn];
int n, lg[maxn];
int minn[23][maxn], maxx[23][maxn];

int qrymin(int l,int r){
    if(r - l + 1 <= 0)return 0x3f3f3f3f3f3f3f;
    int k = lg[r - l + 1];return min(minn[k][l],minn[k][r - (1 << k) + 1]);
}
int qrymax(int l,int r){
    if(r - l + 1 <= 0)return -0x3f3f3f3f3f3f3f;
    int k = lg[r - l + 1];return max(maxx[k][l],maxx[k][r - (1 << k) + 1]);
}

int qryl(int x){
    int l = x, r = n, mid = 0;
    while(r - l >= 0){
        mid = l + r >> 1;
        if(qrymax(x,mid) < qrymin(x,mid)){l = mid + 1;}
        else r = mid - 1;
    }
    if(l <= n && qrymin(x,l) == qrymax(x,l))return l;
    return -1;
}
int qryr(int x){
    int l = x, r = n, mid = 0;
    while(r - l >= 0){
        mid = l + r >> 1;
        if(qrymax(x,mid) > qrymin(x,mid)){r = mid - 1;}
        else l = mid + 1;
    }
    if(r > 0 && qrymin(x,r) == qrymax(x,r))return r;
    return -1;
}
int query(int x){
    int l = qryl(x), r = qryr(x);
    // printf("x = %lld, l = %lld, r = %lld\n",x,l,r);
    // for(int i = x;i <= n;i++){
    //     printf("i = %lld : min=%lld max=%lld\n",i,qrymin(x,i),qrymax(x,i));
    // }
    if(l == -1 || r == -1)return 0;
    return r - l + 1;
}

signed main(){
    n = read();lg[0] = -1;
    for(int i = 1;i <= n;i++){lg[i] = lg[i >> 1] + 1;a[i] = read();maxx[0][i] = a[i];}
    for(int i = 1;i <= n;i++){b[i] = read();minn[0][i] = b[i];}
    for(int k = 1;k <= 22;k++)
        for(int i = 1;i + (1 << k) -  1 <= n;i++){
            maxx[k][i] = max(maxx[k - 1][i],maxx[k - 1][i + (1 << k - 1)]);
            minn[k][i] = min(minn[k - 1][i],minn[k - 1][i + (1 << k - 1)]);
        }
    int ans = 0;
    for(int l = n;l;l--){ans += query(l);}
    printf("%lld\n",ans);
    return 0;
}

CF689E

link

CF689E题意

数轴上有 n n n 条线段,每条线段的端点为 l i l_i li r i r_i ri
众所周知,在 n n n 条线段中取 k k k 条线段有 ( n k ) n \choose k (kn) C n k C_n^k Cnk
种方案,现在每种方案的贡献为这 k k k 条线段交集包含的整点个数(即交集那条线段的长度 + 1 +1 +1),求所有方案的贡献和 m o d   1 0 9 + 7 mod\space 10^9+7 mod 109+7

CF689E题解

这里有野生的水紫,快来切啊(bushi)
离散化,差分两步走,得出每一段线段被覆盖几次。
发现对于覆盖次数 c n t i ≥ k cnt_i\ge k cntik 的线段,贡献是 ( c n t i k ) cnt_i\choose k (kcnti),即从覆盖它的线段中选出 k k k 条满足条件的来求并集的方案数。
然后就没了,根本不用什么数据结构。

CF689E代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 1e6 + 10,mod = 1e9 + 7;
int n, k, cf[maxn];
int l[maxn], r[maxn], x[maxn], tot;
int pw[maxn], pwinv[maxn];
int qpow(int x,int a){
    int res = 1;
    while(a){
        if(a & 1)res = res * x % mod;
        x = x * x % mod;a >>= 1;
    }
    return res;
}
signed main(){
    n = read();k = read();pw[0] = 1;
    for(int i = 1;i <= n;i++){
        x[++tot] = l[i] = read();
        x[++tot] = r[i] = read() + 1;
        pw[i] = pw[i - 1] * i % mod;
    }
    pwinv[n] = qpow(pw[n],mod - 2);
    for(int i = n - 1;i;i--)pwinv[i] = pwinv[i + 1] * (i + 1ll) % mod;
    pwinv[0] = 1;

    // for(int i = 1;i <= n;i++){printf("i = %lld,tim = %lld\n",i,pwinv[i] * pw[i] % mod);}

    sort(x + 1,x + 1 + tot);tot = unique(x + 1,x + 1 + tot) - x - 1;
    for(int i = 1;i <= n;i++){
        l[i] = lower_bound(x + 1,x + 1 + tot,l[i]) - x;
        r[i] = lower_bound(x + 1,x + 1 + tot,r[i]) - x;
        cf[l[i]]++;cf[r[i]]--;
    }
    int ans = 0;
    for(int i = 1;i < tot;i++){
        cf[i] += cf[i - 1];if(cf[i] < k)continue;
        int len = x[i + 1] - x[i];
        ans = (ans + pw[cf[i]] * pwinv[cf[i] - k] % mod * pwinv[k] % mod * len % mod) % mod;
    }
    printf("%lld\n",ans);
    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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值