zoukankan      html  css  js  c++  java
  • Codeforces Round #677 (Div. 3)

    写在前面

    最近开始刷CF,今天第一次补完完整的一套CF,总结一下吧,发现做过的题不赶紧总结写题解就容易忘了。
    立个flag 争取每天更新一篇CF题解

    A. Boring Apartments

    模拟题,模拟就完了

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    int sum, a[100005];
    int main(){
        for (int i = 1; i <= 9;i++){
            for (int j = 1; j <= 4;j++){
                sum += j;
                int temp = i;
                for (int k = 1; k < j;k++){
                    temp = temp * 10 + i;
                }
                a[temp] = sum;
            }
        }
        int n;
        cin >> n;
        while(n--){
            int x;
            cin >> x;
            cout << a[x] << endl;
        }
        return 0;
    }
    

    B. Yet Another Bookshelf

    大意: 1代表有书,0代表没有书,对于每次操作,可以将一段连续的1整体向左或向右移动,问将全部的1移到一起最少要多少步
    思路: 直接计算中间的0有多少个就行

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    int t, n;
    int main(){
        cin>>t;
        while(t--){
            cin>>n;
            int x,flag=0,cnt=0,cnt0=0;
            for (int i = 0; i < n;i++){
                cin >> x;
                if(x==1&&flag==0){
                    flag = 1;
                }
                else if(flag==1&&x==0){
                    cnt++;
                    cnt0++;
                }
                else if(x==1&&flag==1){
                    cnt0 = 0;
                }
            }
            cout << cnt - cnt0 << endl;
        }
        return 0;
    }
    

    C. Dominant Piranha

    大意: 给一个数组a,对于任意一个元素a[i],如果它大于相邻的元素,可以将这个较小的元素吃掉,然后自己的值增加1,问能否找到一个元素,不断吃掉相邻的元素,最终吃掉除自己之外的整个数组。
    思路: 对于一个数组,如果所有的元素都相同,那么必然找不到可以吃的元素;否则就找到最大的元素,如果最大的元素有多个,则找到存在较小相邻元素的那个即可,因为这样它可以通过吃掉这个较小的元素,从而成为唯一的最大的元素。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 3e5 + 5;
    int t, n, maxn, anss,x,a[N],flag=0;
    int main(){
        cin>>t;
        while(t--){
            cin >> n;
            maxn = -1;
            for (int i = 1; i <= n;i++){
                cin >> a[i];
                maxn = max(maxn, a[i]);
            }
            anss = -1;
            for (int i = 1; i <= n;i++){
                if(i==1){
                    if(a[i]==maxn&&a[i+1]!=a[i]){
                        anss = i;
                        break;
                    }
                }
                else if(i==n){
                    if(a[i]==maxn&&a[i-1]!=a[i]){
                        anss = i;
                        break;
                    }
                }
                else{
                    if(a[i]==maxn&&(a[i-1]!=a[i]||a[i+1]!=a[i])){
                        anss = i;
                        break;
                    }
                }
            }
            cout << anss << endl;
        }
        return 0;
    }
    

    D. Districts Connection

    大意: 给出n个数,其中 (a_i)代表第i个街区属于第(a_i)个帮派,相同帮派之间的街区不能直连,问能否得到符合条件的树,使得所有的街区都联通
    思路: 直接构造即可,因为不同的街区之间不能直连,所以将所有和第一个街区所属帮派不同的街区和第一个街区相连,然后将和第一个街区的帮派相同的街区与 和第一个街区相连的一个街区 相连即可。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    int t, n,other,a[5005];
    vector<int> anss[2];
    int main(){
        cin>>t;
        while(t--){
            cin >> n;
            other = 0;
            anss[0].clear();
            anss[1].clear();
            for (int i = 1; i <= n;i++){
                cin >> a[i];
                if(a[i]!=a[1]){
                    anss[0].push_back(i);
                    other = i;
                }
            }
            if(other==0){
                cout << "NO" << endl;
            }
            else{
                cout << "YES" << endl;
                for (int i = 2; i <= n;i++){
                    if(a[i]==a[1]){
                        anss[1].push_back(i);
                    }
                }
                for (int i = 0; i < anss[0].size();i++){
                    cout << 1 << ' ' << anss[0][i] << endl;
                }
                for (int i = 0;i<anss[1].size();i++){
                    cout << other << ' ' << anss[1][i] << endl;
                }
            }
        }
        return 0;
    }
    

    E. Two Round Dances

    大意: 将n个人分成两组,对于每一组都是一个环,问有多少种不同的分法,注意对于一个环来说 1234 和 4123是相同的
    思路: 一开始不会,搜了一下才知道这是圆排列数
    圆排列的定义为: 有一组元素,将其排成一个圆,这种排列叫做圆排列或项链排列。
    一般地,有m个元素作圆排列,其计算公式为 ((m-1)!)

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    long long anss=1,n;
    int main(){
        cin>>n;
        for (int i = (n / 2) + 1; i <= n; i++){
            anss *= i;
        }
        for (int i = 1; i <= (n / 2);i++){
            anss /= i;
        }
        for (int i = (n / 2) - 1; i >= 1;i--){
            anss *= i;
        }
        for (int i = (n / 2) - 1; i >= 1;i--){
            anss *= i;
        }
        cout << anss / 2 << endl;
        return 0;
    }
    

    F. Zero Remainder Sum

    大意: 每行只能选择(leftlfloorfrac{m}{2} ight floor)个元素,问选出的元素和满足能被&k&整除的最大值是多少
    思路: 看题解说是经典dp问题,可是我不会qwq....
    (dp[x][y][cnt][rem])代表当前位置为((x,y)) 已经选取了(cnt)个元素且余数是(rem)
    那么
    (dp[1][1][0][0]=0)代表最初的位置
    (dp[nx][ny][cnt][rem] = max(dp[nx][ny][cnt][rem],dp[x][y][cnt][rem])) 表示不取当前元素
    (dp[nx][ny][cnt + 1][(rem+a_{ij})\%k] = max(dp[nx][ny][cnt+1][(rem+a_{ij})\%k],dp[x][y][cnt][rem] + a_{ij})) 表示取当前元素
    然后一行一行的扫过去就行,最后输出(dp[n+1][1][0][0])

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 70 + 5;
    int a[N][N], dp[N][N][N][N], n, m, k;
    int main(){
        cin >> n >> m >> k;
        for (int i = 1; i <= n;i++){
            for (int j = 1; j <= m;j++){
                cin >> a[i][j];
            }
        }
        memset(dp, -1, sizeof(dp));
        dp[1][1][0][0] = 0;
        for (int i = 1; i <= n;i++){
            for (int j = 1; j <= m;j++){
                for (int cnt = 0; cnt <= (m / 2);cnt++){
                    for (int rem = 0; rem < k;rem++){
                        if(dp[i][j][cnt][rem]==-1){
                            continue;
                        }
                        int ii=i, jj=j+1;
                        if(j==m){
                            jj = 1;
                            ii = i + 1;
                        }
                        if(ii==i){
                            dp[ii][jj][cnt][rem] = max(dp[ii][jj][cnt][rem], dp[i][j][cnt][rem]);
                        }
                        else{
                            dp[ii][jj][0][rem] = max(dp[ii][jj][0][rem], dp[i][j][cnt][rem]);
                        }
                        if((cnt+1)<=m/2){
                            if(ii==i){
                                dp[ii][jj][cnt+1][(rem+a[i][j])%k] = max(dp[ii][jj][cnt+1][(rem+a[i][j])%k], dp[i][j][cnt][rem]+a[i][j]);
                            }
                            else{
                                dp[ii][jj][0][(rem+a[i][j])%k] = max(dp[ii][jj][0][(rem+a[i][j])%k], dp[i][j][cnt][rem]+a[i][j]);
                            }
                        }
                    }
                }
            }
        }
        cout << max(0, dp[n + 1][1][0][0]) << endl;
        return 0;
    }
    

    G. Reducing Delivery Cost

    大意: n个点m个边,可以把其中一个边权值变为0,给出k对起点与终点,问这k对点的距离和最小可以是多少
    思路: 首先跑n次堆优化的dijsktra算法,由于数据较小,可以枚举被删除的边,然后暴力算就行
    注意删除一条边((u,v))后,需要用(min(dis[sx][tx], min(dis[sx][u] + dis[v][tx], dis[sx][v] + dis[u][tx])))来更新
    板子是队友的板子,看了好久才明白...

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e3 + 5;
    int n, m, k;
    typedef pair<int, int> PII;
    int e[2*N], ne[2*N],w[2*N], h[N], idx,dis[N][N], st[N],mp[N][N],anss=0x3f3f3f3f;
    struct node
    {
        int a, b, c;
    };
    
    void add(int a, int b, int c) {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    }
    
    // 堆优化版dijksyta
    int dijkstra(int sx) {
        memset(dis[sx], 0x3f, sizeof dis[sx]);  // 初始化距离为无穷
        memset(st, 0, sizeof st);
        priority_queue<PII, vector<PII>, greater<PII> > q;  // 定义一个按照距离从小到大排序的优先队列,第一维:距离,第二维:点
        dis[sx][sx] = 0;  // 一开始源点距离为0
        q.push({0, sx});  // 把源点信息放入队列
        while (q.size()) {  // 每个点只出入队列一次
            auto t = q.top();
            q.pop();
            
            int distance = t.first, ver = t.second;  // 最小距离和相对应的点
            if (st[ver]) continue;  // 这个操作保证每个点只出入队一次,因为队列里面可能会出现{dis1[3], 3}, {dis2[3], 3}的情况,这样保证dis1[3]<dis2[3]时,3号点只进出入队一次
            st[ver] = 1;  // 标记,因为dijkstra的贪心策略保证每个点只需要进出队一次
            
            for (int i = h[ver]; ~i; i = ne[i]) {  // 遍历ver的邻接点
                int j = e[i];
                if (dis[sx][j] > distance + w[i]) {
                    dis[sx][j] = distance + w[i];
                    q.push({dis[sx][j], j});  // 这里不需要判断st,因为一旦更新发现更小必须放入队列
                }
            }
        }
    }
    
    
    struct road
    {
        int u, v, w;
    };
    
    vector<struct road> r;
    vector<pair<int, int> >q;
    int main(){
        cin >> n >> m >> k;
        memset(h, -1, sizeof h);
        //memset(mp, 0x3f, sizeof mp);  // 初始更新每个点间距离为无穷远
        for (int i = 0; i < m;i++){
            int x, y, z;
            struct road node;
            cin >> node.u >> node.v >> node.w;
            r.push_back(node);
            add(node.u, node.v, node.w);
            add(node.v, node.u, node.w);
            //mp[node.u][node.v] = min(node.w,mp[node.u][node.v]);
        }
        for (int i = 1; i <= n;i++){
            dijkstra(i);
        }
        for (int i = 0; i < k; i++)
        {
            int sx, tx;
            cin >> sx >> tx;
            q.push_back({sx, tx});
        }
        for (int i = 0; i < r.size();i++){
            int temp = 0;
            for (int j = 0; j < q.size();j++){
                int sx = q[j].first;
                int tx = q[j].second;
                temp += min(dis[sx][tx], min(dis[sx][r[i].u] + dis[r[i].v][tx], dis[sx][r[i].v] + dis[r[i].u][tx]));
            }
            anss = min(temp, anss);
        }
        cout << anss << endl;
        return 0;
    }
    
  • 相关阅读:
    英语4月测试题
    Hadoop---集群的时间同步
    Hadoop---日志服务器
    Hadoop---桥接集群的搭建
    HDFS
    虚拟机类加载机制
    Hadoop---集群的搭建(仅主机模式)
    YARN
    垃圾收集算法和垃圾收集器
    Hadoop---HDFS读写流程
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/13997876.html
Copyright © 2011-2022 走看看